为了处理容器内的数据, STL 为我们提供了一系列的算法 包括 查找 排序 拷贝 重新排序 修改 数值运算等基本而普遍的算法.
算法并不是容器的成员函数,而是一种搭配迭代器使用的全局函数,这样做大幅减少程序的代码量,提高程序库的能力和弹性
先从 STL 简单的算法开始, 算法在 < algorithm > 包下,
#include <iostream>
#include <vector>
#include <algorithm>
/**
* 在迭代器的使用过程中,尽量使用 const_iterator 迭代器,
* 来保证数据的准确性,防止被他人修改
*/
void tsm_algorithm(){
vector<int> tsm={4,2,5,6,1,3,5,3,2,7};
// 求最小值
auto min=min_element(tsm.cbegin(),tsm.cend());
cout<<"min:"<< *min<<endl;
//求最大值
auto max=max_element(tsm.cbegin(),tsm.cend());
cout << "max:"<< *max<<endl;
// 排序 ,不能使用 const_iterator,只读无法更改数据
sort(tsm.begin(),tsm.end());
for(auto item:tsm){
cout<<"排序后遍历:" <<item<<endl;
}
// 查找
auto index= find(tsm.cbegin(),tsm.cend(),9);
if(index==tsm.cend()){
cout <<"查找失败"<<endl;
}else{
cout <<"查找成功后的结果:"<< *index <<endl;
}
//反转数据 不能使用 const_iterator,只读无法更改数据
reverse(tsm.begin(),tsm.end());
for(auto item:tsm){
cout<<"反转后遍历:" <<item<<endl;
}
}
结果:
D:\CWorkSpace\tsmTest\cmake-build-debug\tsmTest.exe
min:1
max:7
排序后遍历:1
排序后遍历:2
排序后遍历:2
排序后遍历:3
排序后遍历:3
排序后遍历:4
排序后遍历:5
排序后遍历:5
排序后遍历:6
排序后遍历:7
查找失败
反转后遍历:7
反转后遍历:6
反转后遍历:5
反转后遍历:5
反转后遍历:4
反转后遍历:3
反转后遍历:3
反转后遍历:2
反转后遍历:2
反转后遍历:1
Process finished with exit code 0
在迭代器的使用过程中,尽量使用 const_iterator 迭代器,来保证数据的准确性,防止被他人修改
这里先从 min_element 这迭代器来看看他的源码是如何实现的
template<typename _ForwardIterator>
_GLIBCXX14_CONSTEXPR
_ForwardIterator
inline min_element(_ForwardIterator __first, _ForwardIterator __last)
{
// concept requirements
__glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>)
__glibcxx_function_requires(_LessThanComparableConcept<
typename iterator_traits<_ForwardIterator>::value_type>)
__glibcxx_requires_valid_range(__first, __last);
__glibcxx_requires_irreflexive(__first, __last);
return _GLIBCXX_STD_A::__min_element(__first, __last,
__gnu_cxx::__ops::__iter_less_iter());
}
template<typename _ForwardIterator, typename _Compare>
_GLIBCXX14_CONSTEXPR
_ForwardIterator
__min_element(_ForwardIterator __first, _ForwardIterator __last,
_Compare __comp)
{
if (__first == __last)
return __first;
_ForwardIterator __result = __first;
while (++__first != __last)
if (__comp(__first, __result))
__result = __first;
return __result;
}
在 min_element 方法中,拿到 first 和 end 迭代器,同时使用 first 和 end 外加 __gnu_cxx::__ops::__iter_less_iter() 这个方法一起调用了 __min_element 这个方法,
在 __min_element 方法中 先判断开始与结束是否一致,如果一致则返回first ,不一致则 使用while 循环调用 compare 方法,来获取最小值
我们再来介绍一下find 方法,因为find 可能存在两种情况,一种是找到了,一种是没找到,那么一个指针如何来判断是否找到呢,来看看他的源码
template<typename _InputIterator, typename _Tp>
inline _InputIterator
find(_InputIterator __first, _InputIterator __last,
const _Tp& __val)
{
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
__glibcxx_function_requires(_EqualOpConcept<
typename iterator_traits<_InputIterator>::value_type, _Tp>)
__glibcxx_requires_valid_range(__first, __last);
return std::__find_if(__first, __last,
__gnu_cxx::__ops::__iter_equals_val(__val));
}
template<typename _Iterator, typename _Predicate>
inline _Iterator
__find_if(_Iterator __first, _Iterator __last, _Predicate __pred)
{
return __find_if(__first, __last, __pred,
std::__iterator_category(__first));
}
inline _InputIterator
__find_if(_InputIterator __first, _InputIterator __last,
_Predicate __pred, input_iterator_tag)
{
while (__first != __last && !__pred(__first))
++__first;
return __first;
}
可以看到find 其实是与 min_element 的写法是非常类似的,整个过程都是在不断的从first 向 end 处遍历,如果遍历不到最后返回的指针应该与 end 重叠,我们只要判断返回的 iterator 是否与 end 重叠即可知道是否查找成功
也就是我在案例中使用的
auto index= find(tsm.cbegin(),tsm.cend(),9);
if(index==tsm.cend()){
cout <<"查找失败"<<endl;
}else{
cout <<"查找成功后的结果:"<< *index <<endl;
}
这个里面还有一个非常小的细节,那就是在传入 first 和 end 时,不能同时传入 iterator 与 const_iterator ,下面这个就是不允许的
auto min=min_element(tsm.cbegin(),tsm.end());
在上面同时使用了 cbegin 和 end ,编译器会提示你使用方式不正确,原因是
template<typename _ForwardIterator>
所有的方法只接受一种 template ,cbegin 和 end 是两种类型,所以不可以