STL——算法

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个最值
  • 该算法的作用是找前 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值