STL简单<stl_algorithms.h>算法的实现

1.简介

STL标准中,没有区分基本算法和复杂算法,然而SGI STL却把常用的算法定义在<stl_algorithms.h>中。本文介绍部分<stl_algorithms.h>算法的实现,给出实现代码和测试代码。

本文介绍的算法包括:

1.      mismatch:比较两个序列,指出两者之间第一个不匹配的点,返回一对迭代器,分别指向两序列中不匹配的点;

2.      equal:如果两个序列在 [first, last ] 区间内相等,equal() 返回true,忽略第二个序列的元素多出来的部分;

3.      fill:将 [ first,last ) 内的所有元素值改填为 value;

4.      fill_n:将 [ first,last ) 内的前 n 个元素值改填为 value ,返回迭代器,指向被填入的最后一个元素的下一位置;

5.      iter_sawp:将两个迭代器(ForwardIterator)所指的对象对调;

6.      lexicographical_compare:以“字典排列方式”对两个序列 [first1, last1 ) 和 [ first2, last2 )进行比较;

7.      max、min:比较大小;

2.设计与实现

我用VS2013写的程序(github),数值算法的实现版本的位于cghSTL/version/cghSTL-0.5.2.rar

本文介绍的算法实现需要以下文件:

1.    cghVector.h,自己实现的vector,位于cghSTL/sequence
containers
/cghVector/,想了解vector实现细节的同学请移步:STL简单vector的实现

2.      cghUtil.h:算法的输出会用到pair结构体,我把pair自己实现了一遍,位于cghSTL/cghUtil/

3.    cghStl_algobase.h,本文的主角:算法的源码,位于cghSTL/algorithms/

4.   test_algorithms_algobase.cpp,测试文件,位于cghSTL/test/

为了增强代码的可读性,我用region把各个算法隔开,如下图所示

copy算法的实现略微复杂,单独开博客介绍,其余的算法都很简单,直接上代码吧,注释已经说明了一切~

cghStl_algobase.h

/*******************************************************************
*  Copyright(c) 2016 Chen Gonghao
*  All rights reserved.
*
*  [email protected]
*
*  文件内容:equal、fill、fill_n、iter_sawp、max、min、
			 lexicographical_compare、mismatch、copy 算法的实现
******************************************************************/

#ifndef _CGH_STL_ALGOBASE_
#define _CGH_STL_ALGOBASE_

#include "cghUtil.h"
#include "cghSTL_type_traits.h"
#include "cghSTL_iterator.h"

namespace CGH{

	#pragma region equal

	/* 如果两个序列在 [ first, last ] 区间内相等,equal() 返回true,忽略第二个序列的元素多出来的部分 */
	template<class InputIterator1, class InputIterator2>
	inline bool equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2)
	{
		for (; first1 != last1; ++first1, ++first2)
		{
			if (*first1 != *first2)
			{
				return false ; // 如果同一位置上的两个元素值不相等,返回false
			}
		}
		// 当第一个序列走完时(第二个序列一定要比第一个长,且不考虑第二个序列多出来的部分)
		// 两个序列相同位置的元素全部相等,返回true
		return true ;
	}

	/*
		如果两个序列在 [ first, last ] 区间内相等,equal() 返回true,忽略第二个序列的元素多出来的部分
		binaryPredicate:用户自定义的比较函数
	*/
	template<class InputIterator1, class InputIterator2, class binaryPredicate>
	inline bool equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, binaryPredicate binary_pred)
	{
		for (; first1 != last1; ++first1, ++first2)
		{
			if (!(binaryPredicate(*first1, *first2)))
			{
				return false ; // 如果同一位置上的两个元素值不相等(采用用户自定义的大小比较函数:binaryPredicate),返回false
			}
		}
		// 当第一个序列走完时(第二个序列一定要比第一个长,且不考虑第二个序列多出来的部分)
		// 两个序列相同位置的元素全部相等,返回true
		return true ;
	}

	#pragma endregion

	#pragma region fill

	/* 将 [ first, last ) 内的所有元素值改填为 value */
	template<class ForwardIterator, class T>
	void fill(ForwardIterator first, ForwardIterator last, const T& value)
	{
		for (; first != last; ++first)
		{
			*first = value ;
		}
	}

	#pragma endregion

	#pragma region fill_n

	/* 将 [ first, last ) 内的前 n 个元素值改填为 value ,返回迭代器,指向被填入的最后一个元素的下一位置 */
	template<class OutputIterator, class size, class T>
	OutputIterator fill_n(OutputIterator first, size n, const T& value)
	{
		for (; n > 0; --n, ++first)
		{
			*first = value;
		}
		return first;
	}

	#pragma endregion

	#pragma region iter_sawp

	/* 将两个迭代器(ForwardIterator)所指的对象对调 */
	template<class ForwardIterator1, class ForwardIterator2>
	void iter_swap(ForwardIterator1 first, ForwardIterator2 last)
	{
		// iterator_traits:特性萃取机,获得迭代器指向的值类型
		std::iterator_traits<ForwardIterator1>::value_type tmp = *first;
		*first = *last;
		*last = tmp;
	}

	#pragma endregion

	#pragma region max  min

	/* 比较大小 */
	template<class T>
	inline const T& max(const T& a, const T& b)
	{
		return a > b ? a : b ;
	}

	/* compare:用户自定义的大小比较函数 */
	template<class T, class compare>
	inline const T& max(const T& a, const T& b, compare comp)
	{
		return comp(a, b) ? a : b ;
	}

	/* 比较大小 */
	template<class T>
	inline const T& min(const T& a, const T& b)
	{
		return a < b ? a : b ;
	}

	/* compare:用户自定义的大小比较函数 */
	template<class T, class compare>
	inline const T& min(const T& a, const T& b, compare comp)
	{
		return comp(a, b) ? b : a ;
	}

	#pragma endregion

	#pragma region lexicographical_compare

	/*
		以“字典排列方式”对两个序列 [ first1, last1 ) 和 [ first2, last2 )进行比较,第一个序列以字典排序不小于第二个序列
		比较操作针对两个序列中对应位置上的元素进行,直到一下情况出现:
		1.两序列同一位置上的元素不相等;
		2.同时到达 last1 和 last2(两序列相等);
		3.到达 last1 或者 last2(两序列不相等);
	*/
	/*
		两序列第一次出现同一位置上元素不相等时,lexicographical_compare() 函数的返回值有一下可能:
		1.如果第一个序列的元素比较小,返回 true ,否则返回 false;
		2.如果到达 last1 而尚未到达 last2,返回 true;
		3.如果到达 last2 而尚未到达 last1,返回 false;
		4.如果同时到达 last1 和 last2(注意,序列的区间是前闭后开,同时到达 last 说明所有元素都匹配),返回false;
	*/
	template<class InputIterator1, class InputIterator2>
	bool lexicographical_compare(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2)
	{
		// 以下任何一个序列到达尾端,就结束。,否则两序列一一比对相应元素
		for (; first1 != last1 && first2 != last2; ++first1, ++first2)
		{
			if (*first1 < *first2)
			{
				return true ; // 第一序列值小于第二序列相应值,返回 true
			}
			if (*first2 < *first1)
			{
				return false ; // 第一序列值大于第二序列相应值,返回 false
			}
			// 如果两序列同一位置元素相等,进入迭代器前进,下一轮比较
		}
		// 如果第一个序列到达尾端,但是第二个序列仍有剩余,那么第一个序列小于第二个序列
		return first1 == last1 && first2 != last2 ;
	}

	/* compare:用户指定的大小比较方法 */
	template<class InputIterator1, class InputIterator2, class compare>
	bool lexicographical_compare(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, compare comp)
	{
		for (; first1 != last1 && first2 != last2; ++first1, ++first2)
		{
			if ( comp( *first1, *first2 ) )
			{
				return true ;
			}
			if ( comp(*first2, *first1) )
			{
				return false ;
			}
		}
		return first1 == last1 && first2 != last2 ;
	}

	/* 为了增强效率,设计了特化版,使用原生指针 const unsigned char* */
	bool lexicographical_compare(const unsigned char* first1, const unsigned char* last1, const unsigned char* first2, const unsigned char* last2)
	{
		const size_t len1 = last1 - first1 ; // 第一个序列的长度
		const size_t len2 = last2 - first2 ; // 第二个序列的长度
		const int result = memcmp(first1, first2, CGH::min(len1, len2)); // 使用memcmp比较长度相同的部分
		return result != 0 ? result < 0 : len1 < len2 ; // 如果不相上下,则长度较长者视为比较大
	}
	#pragma endregion

	#pragma region mismatch

	/*
		比较两个序列,指出两者之间第一个不匹配的点,返回一对迭代器,分别指向两序列中不匹配的点
		如果两序列对应元素都匹配,返回的便是两序列各自的 last 迭代器
		如果第二个序列比第一个序列长,忽略多出来的部分
		默认情况下是 equality 操作符比较元素
	*/
	template<class InputIterator1, class InputIterator2>
	cghPair<InputIterator1, InputIterator2> mismatch(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2)
	{
		while (first1 != last1 && *first1 == *first2)
		{
			++first1;
			++first2;
		}
		return cghPair<InputIterator1, InputIterator2>(first1, first2) ;
	}

	/* BinaryPredicator:用户自定义比较操作 */
	template<class InputIterator1, class InputIterator2, class BinaryPredicator>
	cghPair<InputIterator1, InputIterator2> mismatch(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, BinaryPredicator binary_pre)
	{
		while (first1 != last1 && binary_pre(*first1, *first2))
		{
			++first1;
			++first2;
		}
		return cghPair<InputIterator1, InputIterator2>(first1, first2) ;
	}

	#pragma endregion

}

#endif

3.测试

测试环节的主要内容已在注释中说明

test_algorithms_algobase.cpp

/*******************************************************************
*  Copyright(c) 2016 Chen Gonghao
*  All rights reserved.
*
*  [email protected]
*
*  文件内容:cghStl_algobase.h 中的数值算法的测试
******************************************************************/

#include "stdafx.h"
#include "cghVector.h"
#include "cghStl_algobase.h"
#include <string>
#include <iterator>
#include "cghUtil.h"

int _tmain(int argc, _TCHAR* argv[])
{
	using namespace::CGH;

	std::cout << "创建vector1,依次 puah_back 1、2、3、4、5" << std::endl << std::endl;
	cghVector<int> vector1;
	vector1.push_back(1);
	vector1.push_back(2);
	vector1.push_back(3);
	vector1.push_back(4);
	vector1.push_back(5);
	std::cout << "创建vector2,依次 puah_back 1、2、8、9、0" << std::endl << std::endl;
	cghVector<int> vector2;
	vector2.push_back(1);
	vector2.push_back(2);
	vector2.push_back(8);
	vector2.push_back(9);
	vector2.push_back(0);
	std::ostream_iterator<int> oite(std::cout, " ");

	std::cout << "***********************测试 mismatch 算法**********************" << std::endl << std::endl;
	std::cout << "返回一对迭代器,指出 vector1 和 vector2 的第一个不相等元素:" ;
	std::cout << *(CGH::mismatch(vector1.begin(), vector1.end(), vector2.begin()).first) << ", ";
	std::cout << *(CGH::mismatch(vector1.begin(), vector1.end(), vector2.begin()).second);
	std::cout << std::endl << std::endl << std::endl;

	std::cout << "************************测试 equal 算法************************" << std::endl << std::endl;
	std::cout << "判断 vector1 和 vector2 是否相等:";
	std::string isEqual = equal(vector1.begin(), vector1.end(), vector2.begin(), vector2.end()) == 0 ? "不相等" : "相等" ;
	std::cout << isEqual << std::endl << std::endl;

	std::cout << "用户指定 less<int>() 函数,判断 vector1 和 vector2 的大小:";
	std::string isLess = equal(vector1.begin(), vector1.end(), vector2.begin(), std::less<int>()) == 0 ? "vector1 小于 vector2" : "vector1 大于 vector2" ;
	std::cout << isLess << std::endl << std::endl << std::endl;

	std::cout << "*************************测试 fill 算法************************" << std::endl << std::endl;
	std::cout << "将 vector1 的所有元素改填为 9:" << std::endl << std::endl;
	CGH::fill(vector1.begin(), vector1.end(), 9);
	for (int i = 0; i < vector1.size(); ++i)
	{
		std::cout << "vector1[" << i << "] = " << vector1[i] << std::endl;
	}
	std::cout << std::endl << std::endl;

	std::cout << "************************测试 fill_n 算法***********************" << std::endl << std::endl;
	std::cout << "将 vector1 的前3个元素改填为 0:" << std::endl << std::endl;
	CGH::fill_n(vector1.begin(), 3, 0);
	for (int i = 0; i < vector1.size(); ++i)
	{
		std::cout << "vector1[" << i << "] = " << vector1[i] << std::endl;
	}
	std::cout << std::endl << std::endl;

	std::cout << "***********************测试 iter_sawp 算法**********************" << std::endl << std::endl;
	std::cout << "交换 vector1[0] 和 vector2[0],交换前,vector1[0] = " << vector1[0] << ",vector2[0] = " << vector2[0] << std::endl;
	CGH::iter_swap(vector1.begin(), vector2.begin());
	std::cout << std::endl;
	std::cout << "交换后,vector1[0] = " << vector1[0] << ",vector2[0] = " << vector2[0] << std::endl;
	std::cout << std::endl << std::endl;

	std::cout << "****************测试 lexicographical_compare 算法***************" << std::endl << std::endl;
	std::string str1[] = {"test", "Cgh"};
	std::string str2[] = {"test", "cgh"};
	std::cout << "现有 str1[] = {\"test\", \"Cgh\"}  和  str2[] = {\"test\", \"cgh\"}" << std::endl << std::endl;
	std::cout << "比较 str1[] 和 str2[] 的大小:" ;
	std::string str1Str2 = CGH::lexicographical_compare(str1, str1 + 1, str2, str2 + 1) == true ? "str1[] 大于 str2[]" : "str1[] 小于 str2[]";
	std::cout << str1Str2 << std::endl;
	std::cout << std::endl << std::endl;

	std::cout << std::endl;
	system("pause");
	return 0;
}

结果如下图所示:

时间: 2024-10-16 10:11:34

STL简单<stl_algorithms.h>算法的实现的相关文章

STL简单 copy 算法的实现

1.简介 不论是对客户端或对STL内部而言,copy() 都是一个常常被调用的函数.由于copy进行的是复制操作,而复制操作不外乎运用赋值运算符(assignment operator)或复制构造函数(copy constructor),但是某些元素的类型是trivial assignment operator,因此如果能使用内存直接进行复制(例如使用C标准函数memmove.memcpy),便能节约大量时间.为此,copy算法用尽各种办法,包括函数重载(function overloading

探讨排序算法的实现

排序算法是我们工作中使用最普遍的算法,常见的语言库中基本都会有排序算法的实现,比如c标准库的qsort,stl的sort函数等.本文首先介绍直接插入排序,归并排序,堆排序,快速排序和基数排序等比较排序算法,然后介绍计数排序,基数排序等具有线性时间的排序算法.本文主要讨论算法的实现方法,并不会过多介绍基本理论. 评价一个排序算法优劣适用与否,一般需要从三个方面来分析 时间复杂度.用比较操作和移动操作数的最高次项表示,由于在实际应用中最在乎的是运行时间的上限,所以一般取输入最坏情况的下的运行时间作为

万年历算法的实现(C语言--gcc编译)

/** cal.c * * 现行的格里历是从儒略历演化而来的.儒略历每4年一个润年,润年366天,平年365天.* 如果从公元1年算的话,那么凡是能够被4整除的都是润年.从天文角度看,儒略历这种 * 历法是有误差的,到16世纪误差已经达到了10天.1582年,罗马教皇对儒略历进行了 * 一次校定,该年的10-5到10-14这10天被抹掉,并规定凡不能被400整除的世纪年不再 * 算为润年,校定之后的儒略历即为现行的格里历. * * 但是英国直到1752年才开始使用格里历,此时时间误差已经达到了1

搜索引擎--范例:中英文混杂分词算法的实现--正向最大匹配算法的原理和实现

纯中文和中英文混杂的唯一区别是,分词的时候你如何辨别一个字符是英文字符还是孩子字符, 人眼很容易区分,但是对于计算机来说就没那么容易了,只要能辨别出中文字符和英文的字符,分词本身就不是一个难题 1:文本的编码问题: utf8:windows下,以utf8格式保存的文本是一个3个字节(以16进制)的BOM的,并且你不知道一个汉字是否是用3位表示,但是英文适合ascii编码一样的 ascii:英文一位,中文两位,并且中文的第一个字节的值是大于128和,不会和英文混淆,推荐 unicode:中文基本是

Bug2算法的实现(RobotBASIC环境中仿真)

移动机器人智能的一个重要标志就是自主导航,而实现机器人自主导航有个基本要求--避障.之前简单介绍过Bug避障算法,但仅仅了解大致理论而不亲自动手实现一遍很难有深刻的印象,只能说似懂非懂.我不是天才,不能看几遍就理解理论中的奥妙,只能在别人大谈XX理论XX算法的时候,自己一个人苦逼的面对错误的程序问为什么... 下面开始动手来实现一下简单的Bug2避障算法.由于算法中涉及到机器人与外界环境的交互,因此需要选择一个仿真软件.常用的移动机器人仿真软件主要有Gazebo.V-rep.Webots.MRD

软考笔记第六天之各排序算法的实现

对于前面的排序算法,用c#来实现 直接插入排序: 每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序.第一趟比较前两个数,然后把第二个数按大小插入到有序表中: 第二趟把第三个数据与前两个数从前向后扫描,把第三个数按大小插入到有序表中:依次进行下去,进行了(n-1)趟扫描以后就完成了整个排序过程.直接插入排序属于稳定的排序,最坏时间复杂性为O(n^2),空间复杂度为O(1).直接插入排序是由两层嵌套循环组成的.外层循环标识并决定待比较的数值.内层循环为待比较数值确定其最终位

冒泡排序算法的实现

/***********冒泡排序算法的实现*********************/#include <stdio.h> void println(int array[], int len){    int i = 0;        for(i=0; i<len; i++)    {        printf("%d ", array[i]);    }        printf("\n");} void swap(int array[],

RMQ问题总结,标准RMQ算法的实现

RMQ问题:对于长度为N的序列,询问区间[L,R]中的最值 RMQ问题的几种解法: 普通遍历查询,O(1)-O(N) 线段树,O(N)-O(logN) DP,O(NlogN)-O(1) RMQ标准算法,O(N)-O(1) 简单介绍: 朴素的查询,不需要任何预处理,但结果是没有任何已知的信息可以利用,每次都需要从头遍历到尾. 线段树,区间问题的神器,用线段树做比起朴素的暴力查询要快得多,关键在于线段树使用了分治思想,利用了区间问题的可合并性.任何一个区间最多只需要logN个线段树上的区间来合并,线

七种排序算法的实现和总结

最近把七种排序算法集中在一起写了一遍. 注释里有比较详细的说明. 1 /*排序算法大集合**/ 2 #include <stdio.h> 3 #include <string.h> 4 #include <stdlib.h> 5 6 //------------------快速排序------------------// 7 /* 8 核心: 9 如果你知道多少人该站你前面,多少人站你后面,你一定知道你该站哪个位置. 10 算法: 11 1.选取分界数,参考这个分界数,