欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STL——算法

程序员文章站 2022-07-12 17:58:36
...

accumulate

  • 该算法作用是对某区间中的元素进行累加,使用时必须添加头文件<numeric>
// 对[first, last)区间中元素在init的基础上进行累加
template <class InputIterator, class T>
T accumulate (InputIterator first, InputIterator last, T init);

// 对[fist, last)区间中元素在init的基础上按照binary_op(可以是仿函数对象、函数指针)指定的操作进行累加
template <class InputIterator, class T, class BinaryOperation>
T accumulate (InputIterator first, InputIterator last, T init, BinaryOperation binary_op);
  • 举例:
struct Mul2{
	int operator()(int x, int y) { return x + 2 * y; }
};
int main(){
	// 对区间中的元素进行累加
	vector<int> v{ 10, 20, 30 };
	cout << accumulate(v.begin(), v.end(), 0)<<endl;
	// 对区间中的每个元素乘2,然后累加
	cout << accumulate(v.begin(), v.end(), 0, Mul2()) << endl;
	return 0;
}

countcount_if

  • 该算法的作用是统计某区间中某个元素出现的次数,使用时必须添加头文件<algorithm>
// 统计value在区间[first,last)中出现的次数
template <class InputIterator, class T>
ptrdiff_t count (InputIterator first, InputIterator last, const T& value);

// 统计满足pred(可以是仿函数对象、函数指针)条件的元素在[first, last)中的个数
template <class InputIterator, class Predicate>
ptrdiff_t count_if (InputIterator first, InputIterator last, Predicate pred);
  • 举例:
bool IsOdd(int i){ 
	return ((i % 2) == 1);
}
int main(){
	// 统计10在v1中出现的次数
	vector<int> v1{ 10, 20, 30, 30, 20, 10, 10, 20 };
	cout << count(v1.begin(), v1.end(), 10) << endl;
	
	// 统计v2中有多少个偶数
	vector<int> v2{0,1,2,3,4,5,6,7,8,9};
	cout << count_if(v2.begin(), v2.end(), IsOdd()) << endl;
	return 0;
}

findfind_if

  • 该算法的作用是找元素在区间中第一次出现的位置,使用时必须包含头文件<algorithm>
// 在[first, last)中查找value第一次出现的位置,找到返回该元素的位置,否则返回last,时间复杂度O(N)
template<class InputIterator, class T>
InputIterator find ( InputIterator first, InputIterator last, const T& value );

// 在[first, last)中查找满足pred(可以是仿函数对象、函数指针)条件的元素第一次出现的位置,找到返回该位置,否则返回last,时间复杂度O(N)
template<class InputIterator, class Predicate>
InputIterator find_if (InputIterator first, InputIterator last, Predicate pred);

maxmin

  • max返回两个元素中较大值,min返回两个元素中较小值,使用时必须包含头文件<algorithm>
template <class T>
const T& max(const T& a, const T& b);

template <class T>
const T& min(const T& a, const T& b);

merge

  • 该算法作用将两个有序序列合并成一个有序序列,使用时必须包含头文件<algorithm>
template <class InputIterator1, class InputIterator2, class OutputIterator>
OutputIterator merge (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2,OutputIterator result);
  • 举例:
int main(){
	vector<int> v{ 2, 6, 5, 8 };
	list<int> L{ 9, 3, 0, 5, 7 };
	sort(v.begin(), v.end());
	L.sort();
	vector<int> vRet(v.size() + L.size());
	merge(v.begin(), v.end(), L.begin(), L.end(), vRet.begin());
	for (auto e : vRet)
		cout << e << " ";
	cout << endl;
	return 0;
}

partial_sort

  • 该算法的作用是找前 K 个最大 / 小的元素,使用时必须包含头文件<algorithm>
// 在区间[first, last)中找前middle-first个最小的元素,并存储在[first, middle)中
template <class RandomAccessIterator>
void partial_sort(RandomAccessIterator first, RandomAccessIterator middle,
RandomAccessIterator last);

// 在[first, last)中找前middle-first个最大或者最小的元素,并存储在[first, middle)中
template <class RandomAccessIterator, class Compare>
void partial_sort(RandomAccessIterator first, RandomAccessIterator middle,
RandomAccessIterator last, Compare comp);
  • 原理:partial_sort的实现原理是:对原始容器内区间为 [first, middle) 的元素执行make_heap()操作,构造一个最大堆,然后拿 [middle, last) 中的每个元素和 first 进行比较,first 内的元素为堆内的最大值,如果小于该最大值,则互换元素位置,并对 [first, middle) 内的元素进行调整,使其保持最大堆序。比较完之后再对 [first, middle) 内的元素做一次堆排序sort_heap()操作,使其按增序排列;
  • 举例:
int main(){
	// 找该区间中前4个最小的元素, 元素最终存储在v1的前4个位置
	vector<int> v1{ 4, 1, 8, 0, 5, 9, 3, 7, 2, 6 };
	partial_sort(v1.begin(), v1.begin() + 4, v1.end());
	
	// 找该区间中前4个最大的元素, 元素最终存储在v1的前4个位置
	vector<int> v2{ 4, 1, 8, 0, 5, 9, 3, 7, 2, 6 };
	partial_sort(v2.begin(), v2.begin() + 4, v2.end(), greater<int>());
	return 0;
}

partition

  • 该算法的作用是按照条件对区间中的元素进行划分,使用时必须包含头文件<algorithm>
template <class BidirectionalIterator, class Predicate>
BidirectionalIterator partition(BidirectionalIterator first, BidirectionalIterator last, Predicate pred);
  • 举例:
bool IsOdd(int i)
{ return (i % 2) == 1; }
int main(){
	vector<int> v{0,1,2,3,4,5,6,7,8,9};
	// 将区间中元素分割成奇数和偶数两部分
	auto div = partition(v.begin(), v.end(), IsOdd);
	// 打印[begin, div)的元素
	for (auto it = v.begin(); it != div; ++it)
		cout << *it <<" ";
	cout << endl;
	// 打印[div, end)的元素
	for (auto it = div; it != v.end(); ++it)
		cout << " " << *it;
	cout << endl;
	return 0;
}

reverse

  • 该算法的作用是对区间中的元素进行逆置,使用时必须包含头文件<algorithm>
template <class BidirectionalIterator>
void reverse ( BidirectionalIterator first, BidirectionalIterator last);

sort

  • 排序在实际应用中需要经常用到,而在目前的排序中,快排平均情况下是性能最好的一种排序,但是快排也有其自身的短板,比如说:元素接近有序、元素量比较大的情况下,直接使用快排时,堪称一场灾难,因此 STL 中sort算法并没有直接使用快排,而是针对各种情况进行了综合考虑,下面关于sort函数分点进行说明:
    1. sort函数提供了两个版本:
      • sort(first, last):默认按照小于方式排序,排序结果为升序,一般用排内置类型数据
      • sort(first, last, comp):可以通过 comp 更改元素比较方式,即可以指定排序的结果为升序或者降序,一般以仿函数对象和函数指针的方式提供;
    2. sort并不是一种排序算法,而是将多个排序算法混合而成;
    3. 当元素个数少于__stl_threshold阈值时 (这个值为 16),使用直接插入排序处理;
    4. 当元素个数超过__stl_threshold时,考虑是否能用快排的方式排序,因为当元素数量达到一定程度,递归式的快排可能会导致栈溢出而崩,因此:
      • 通过__lg函数判断递归的深度;
      • 如果递归的深度没有超过 2 * log2N 时,则使用快排方式排序,注意:快排时使用到了三数取中法预防分割后,一边没有数据的极端情况;
      • 如果递归深度超过 2 * log2N 时,说明数据量大,递归层次太深,可能会导致栈溢出,此时使用堆排序处理;

unique

  • 该函数的作用是删除区间中相邻的重复性元素,确保元素唯一性,注意在使用前要保证区间中的元素是有序的,才能达到真正的去重,使用时必须包含头文件<algorithm>
  • 注意:
    1. 该函数并不是将重复性的元素删除掉,而是用后面不重复的元素将前面重复的元素覆盖掉了;
    2. 返回值是一个迭代器,指向的是去重后容器中不重复最后一个元素的下一个位置;
    3. 该函数需要配合erase才能真正的将元素删除掉;
// 元素不相等时,用后一个将前一个元素覆盖掉
template <class ForwardIterator>
ForwardIterator unique ( ForwardIterator first, ForwardIterator last);

// 如果元素不满足pred(可以是仿函数对象、函数指针)条件时,用后一个将前一个覆盖掉
template <class ForwardIterator, class BinaryPredicate>
ForwardIterator unique ( ForwardIterator first, ForwardIterator last,
BinaryPredicate pred);
  • 举例:
int main(){
	vector<int> v{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
	auto it = unique(v.begin(), v.end());
	for (auto e : v)
		cout << e << " ";
	cout << endl;
	/*
	从打印的结果可以看出:
	1. unique并没有将所有重复的元素删除掉,而值删除了一个9,因为unique删除的是相邻的重复元素,而上述元素中只有一个9重复相邻
	2. unique删除时只是用后面元素将前面重复位置覆盖掉了,并没有达到真正删除,若要真正删除,还需要erase配合
	*/
	v.erase(it, v.end());
	// 如果想将区间中所有重复性的元素删除掉,可以先对区间中的元素进行排序
	for (auto e : v)
		cout << e << " ";
	cout << endl;
	// 先对区间中的元素进行排序,另重复的元素放在相邻位置
	sort(v.begin(), v.end());
	for (auto e : v)
		cout << e << " ";
	cout << endl;
	// 使用unique将重复的元素覆盖掉
	it = unique(v.begin(), v.end());
	// 将后面无效的元素移除
	v.erase(it, v.end());
	for (auto e : v)
		cout << e << " ";
	cout << endl;
	return 0;
}

next_permutationpre_permutation

  • next_permutation是获取一个排序的下一个排列,可以遍历全排列,prev_permutation刚好相反,获取一个排列的前一个排列, 使用时必须包含头文件<algorithm>
  • 举例:
int main(){
	// 因为next_permutation函数是按照大于字典序获取下一个排列组合的
	// 因此在排序时必须保证序列是升序的
	vector<int> v = {4, 1, 2, 3 };
	sort(v.begin(), v.end());
	do{
		cout << v[0] << " " << v[1] << " " << v[2] <<" " <<v[3]<< endl;
	} while (next_permutation(v.begin(), v.end()));
	cout << endl;
	// 因为prev_permutation函数是按照小于字典序获取下一个排列组合的
	// 因此在排序时必须保证序列是降序的
	//sort(v.begin(), v.end());
	sort(v.begin(), v.end(), greater<int>());
	do{
		cout << v[0] << " " << v[1] << " " << v[2] << " " << v[3] << endl;
	} while (prev_permutation(v.begin(), v.end()));
	return 0;
}

上一篇: 第八章

下一篇: STL 算法