文章目录
1,STL算法简介
100多种算法
函数对象(function objects)
函数适配器(function adapters)
三个头文件:<algorithm>, <numeric>, <functional>
预定义的函数对象:
函数对象 | 用法示例及解释 |
---|---|
negate<type>() | 取负操作 |
plus<type>() | 加法操作 |
minus<type>() | 减法操作 |
multiplies<type>() | 乘法操作 |
divides<type>() | 除法操作 |
modulus<type>() | vector<int>::iterator it = find_if(v.begin(), v.end(), not1(bind2nd(modulus<int>(), 3)));取模操作;对容器中每一个元素除3区余数,not1表示取反;该语句含义为查找容器v中第一个能被3整除的数。 |
equal_to<type>() | 等于 |
not_equal_to<type>() | 不等于 |
less<type>() | 小于 |
greater<type>() | vector::iterator it = find_if(v.begin(), v.end(), bind2nd(greater<int>(), 3))); 该语句含义为查找容器v中第一个大于3数。(下面less_equal,greater_equal同理) |
less_equal<type>() | 小于等于 |
greater_equal<type>() | 大于等于 |
logical_not<type>() | 逻辑非 |
logical_and<type>() | 逻辑与 |
logical_or<type>() | 逻辑或 |
预定义的函数适配器
函数适配器 | 示例及解释(下面op为函数对象,value为传入的参数) |
---|---|
bind1st(op, value) | |
bind2nd(op, value) | 解释见上表 |
not1(op) | 取反,解释间上表 |
not2(op) | |
mem_fun_ref(op) | |
mem_fun(op) | |
ptr_fun(op) |
算法分类:
- 非修改性算法(nonmodifying algorithms),不会修改容器中数据的内容
方法 | 解释 |
---|---|
for_each(b, e, 操作); | 对迭代器b到e之间的所有元素执行某操作 |
count(b, e, n); | 返回迭代器b到e之间的所有元素中n的个数 |
count_if(b, e, 谓词); | 返回迭代器b到e之间满足谓词逻辑的所有元素个数 |
min_element(b, e); | 返回指向元素最小值的迭代器 |
max_element(b, e); | 返回指向元素最大值的迭代器 |
find(); | 查找等于某值的第一个元素 |
find_if(); | 查找满足某个条件的第一个元素 |
search(); | 查找某个子区间第一次出现的位置 |
search_n(b, e, n, val); | 在迭代器b到e区间查找是否有n个连续的值为val 的元素,若找到,返回指向连续n个val值中的第一个val的元素位置,否则值为container.end() |
search_n(b, e, n, val, 谓词); | 在迭代器b到e区间查找是否有n个连续的满足谓词条件的元素,若找到,返回指向连续n个val值中的第一个val的元素位置,否则值为container.end() |
find_end(); | 查找某个区间最后一次出现的位置 |
find_fisrt_of(); | 查找等于“某数个值之一”的第一个元素 |
adjacent_find(); | 搜寻连续两个符合特定准则的元素 |
equal(); | 判断两区间是否相等 |
mismatch(); | 返回两个序列的各组对应元素中第一对不相等元素 |
lexicographical_compare(); | 判断某一序列在“字典顺序(lexicographically)”下是否小于另一序列。 |
- 修改性算法(modifying algorithms)
方法 | 解释 |
---|---|
for_each(); | |
copy(); | 从第一个元素开始,复制某段区间 |
copy_backward(); | 从最后一个元素开始,复制某一段区间 |
transform(); | 将两个区间的元素合并 |
merge(); | 合并两个区间 |
swap_ranges(); | 交换两个区间的元素 |
fill(); | 以给定值替换每一个元素 |
fill_n(); | 以给定值替换n个元素 |
generate(); | 以某项操作的结果替换每一个元素 |
generate_n(); | 以某项操作的结果替换n个元素 |
replace(); | 将某项特定值的元素替换为另一元素 |
replace_if(); | 将符合某条件的元素替换为另一元素 |
replace_copy(); | 复制整个区间,同时并将具有某特定值的元素替换为另一元素 |
replace_copy_if(); | 复制整个区间,同时并将符合特定条件的元素替换为另一元素 |
- 移除性算法(removing algorithms)
方法 | 解释 |
---|---|
remove(); | 将某特定值的元素全部移除 |
remove_if(); | 将满足某准则的元素全部移除 |
remove_copy(); | 将不等于某特定值的元素全部复制 |
remove_copy_if(); | 将不满足某特定条件的元素全部复制 |
unique(); | 移除毗邻的重复元素 |
unique_copy(); | 移除毗邻的元素并复制 |
- 变序性算法(mutating algorithms)
方法 | 解释 |
---|---|
reverse(); | 将元素逆序 |
reverse_copy(); | 复制元素,然后逆序 |
rotate(); | 旋转元素次序 |
rotate_copy(); | 得到元素的下一个排列次序 |
next_permutation(); | 得到元素的上一个排列次序 |
prev_permutation(); | 得到元素的下一个排列次序 |
random_shuffle(); | 将元素的次序随机打乱 |
partition(); | 改变元素次序,使“符合某准则”者移到前面 |
stable_partition(); | 与partition()相似,但保持符合条件和不符该合条件的各个元素之间的相对位置 |
- 排序性算法(sorting algorithms)
方法 | 解释 |
---|---|
sort(); | 对所有元素排序 |
stable_sort(); | 对所有元素排序,并保持相等元素间的相对次序排序, |
partial_sort(); | 排序,直到n个元素就位, |
partial_sort_copy(); | 排序,直到n个元素就位,并复制结果 |
nth_element(); | 根据第n个位置进行排序 |
partition(); | 改变元素次序,使符合某准则的元素放在前面 |
stable_partition(); | 与partition()相似,但保持符合条件和不符该合条件的各个元素之间的相对位置 |
make_heap(); | 将一个区间转换成heap |
push_heap(); | 将元素加入一个heap |
pop_heap(); | 从heap中移除一个元素 |
sort_heap(); | 对heap进行排序(执行后不再是heap了) |
- 已序区间算法(sorted range algorithms),在已经排序的基础上对容器中的元素执行操作。
方法 | 解释 |
---|---|
binary_search(); | 判断某区间是否包含某个元素 |
include(); | 判断某区间内的每一个元素是否都涵盖于另一个区间中 |
lower_bound(); | 查找第一个大于给定值的元素 |
upper_bound(); | 查找第一个小于给定值的元素 |
equal_range(); | 返回等于给定值的所有元素构成的区间 |
merge(); | 将两个区间的元素合并 |
set_unique(); | 求两区间并集 |
set_intersection(); | 将两区间交集 |
set_difference(); | 求位于第一区间但不位于第二区间的元素,形成一个已序区间 |
set_symmetric_difference(); | 找出出现于两区间的所有元素,形成一个已序区间 |
inplace_merge(); | 将两个连续的已序区间合并 |
- 数值算法(numeric algorithms)
方法 | 解释 |
---|---|
accumulate(); | 求和 |
inner_product(); | 组合区间内所有元素 |
adjacent_difference(); | 将每个元素和前一元素组合 |
partial_sum(); | 将每个元素和其先前的所有元素组合 |
2,方法
2.1 count 和 count_if 方法
count和count_if对所有容器都是用,是用线性的方法查找,但对于关联容器set和map,有其内部的成员函数:set.count(); multiset.count(); map.count(); multimap.count();它们的速度比通用的count和count_if更快。
#include<iostream>
#include<vector>
#include<set>
#include<algorithm>
#include<functional>
void printValue(int val)
{
std::cout << val << " ";
}
bool isEven(int val)
{
return val % 2 == 0;
}
int main()
{
std::vector<int> vis;
vis.push_back(1); vis.push_back(3); vis.push_back(5); vis.push_back(7);
vis.push_back(1); vis.push_back(4); vis.push_back(7); vis.push_back(1);
std::cout << "容器vis中所有元素:";
for_each(vis.begin(), vis.end(), printValue);
std::cout << std::endl;
int vc = count(vis.begin(), vis.end(), 1); // count函数在algorithm头文件中;
std::cout << "容器vis中1的个数:" << vc << std::endl;
vc = count_if(vis.begin(), vis.end(), isEven); // count_if函数在algorithm头文件中;
std::cout << "容器vis中偶数个数:" << vc << std::endl;
// bind2nd为函数适配器,modulus<int>()函数对象(有两个参数,param1 % param2),param1从迭代器传入,param2人为设定(设为2)
// 下面含义为计数vis容器中奇数(param1 % 2 为1(true))个数
vc = count_if(vis.begin(), vis.end(), std::bind2nd(std::modulus<int>(), 2)); // count_if函数在algorithm头文件中;
std::cout << "容器vis中奇数个数:" << vc << std::endl;
vc = count_if(vis.begin(), vis.end(), std::not1(std::bind2nd(std::modulus<int>(), 2))); // count_if函数在algorithm头文件中;
std::cout << "容器vis中偶数数个数:" << vc << std::endl;
// bind2nd为函数适配器,greater<int>()函数对象(有两个参数,param1 > param2),param1从迭代器传入,param2人为设定(设为3)
// 下面含义为计数vis容器中满足大于3的元素个数
vc = count_if(vis.begin(), vis.end(), std::bind2nd(std::greater<int>(), 3)); //函数适配器bind2nd 在functional头文件中;
std::cout << "容器vis中大于3的元素个数:" << vc << std::endl;
std::multiset<int> mset(vis.begin(), vis.end());
vc = count(mset.begin(), mset.end(), 4);
std::cout << "容器mset中4的个数:" << vc << std::endl;
vc = mset.count(4);
std::cout << "容器mset中4的个数:" << vc << std::endl;
//system("pause");
return 0;
}
2.2 max_element 和 min_element 方法
max_element(b, e);
max_element(b, e, op);
min_element(b, e);
min_element(b, e, op);
#include<iostream>
#include<deque>
#include<algorithm>
//#include<functional>
bool absCompare(int val1, int val2)
{
return abs(val1) < abs(val2);
}
int main()
{
std::deque<int> dq;
for (int i = -15; i <= 9; ++i) dq.push_back(i);
std::cout << "容器dq中的内容:";
for (int i = 0; i < dq.size(); ++i) std::cout << dq[i] << " "; std::cout << std::endl;
std::cout << "容器dq中最小值为:" << *min_element(dq.begin(), dq.end()) << std::endl;
std::cout << "容器dq中最大值为:" << *max_element(dq.begin(), dq.end()) << std::endl;
std::cout << "容器dq中绝对最小值为:" << *min_element(dq.begin(), dq.end(), absCompare) << std::endl;
std::cout << "容器dq中绝对最大值为:" << abs(*max_element(dq.begin(), dq.end(), absCompare)) << std::endl;
//system("pause");
return 0;
}
2.3 查找算法
find(); find_if(); search(); search_n(); find_end(); find_first_of(); adjacent_find() 方法
- find和find_if方法:对所有的容器都是用,是线性的查找算法。 如果对于已序区间,是用相应的已序区间查找算法(binary_search(); includes(); lower_bound(); upper_bound();)更快。 对于关联式容器有等效的成员函数find(),比上述两种通用find方法更合适。 string类型用自己的成员函数find();
- search_n;find_end和search方法
- find_first_of(b, e, sb, se); find_first_of(b, e, sb, se, bp);没有find_last_of,可通过逆向迭代器实现find_last_of的功能。
- adjacent_find(b, e)和adjacent_find(b, e, p)分别用来查找连续的两个相等的和连续两个符合谓词p规则的元素位置。如果对于已序区间,是用相应的已序区间查找算法(binary_search(); includes(); lower_bound(); upper_bound();)更快。 上面7种方法都是线性查找算法。
- binary_search(b,e,sb,se)和includes(b, e, sb, se)方法
- lower_bound; upper_bound(); equal_bound();方法,对于关联容器,有其内部的对应成员函数,用其内部的成员函数更合适。
#include<iostream>
#include<list>
#include<vector>
#include<deque>
#include<set>
#include<string>
#include<algorithm>
#include<functional>
template <typename Container>
void printContainer(const Container& con, std::string str)
{
std::cout << "--------------------------------\n"<< str;
for (Container::const_iterator it = con.begin(); it != con.end(); ++it)
std::cout << *it << " ";
std::cout << std::endl;
}
bool checkEven(int val, bool flag) // 若flag为true,检查val是否为偶数;否则检查其时候为奇数;
{
if (flag) return val % 2 == 0;
else return val % 2 == 1;
}
bool myAdjacent(int val1, int val2)
{
return val1 * 1.5 == val2;
}
int main()
{
std::list<int> lst;
for (int i = 0; i <= 9; ++i) lst.push_back(i);
for (int i = 0; i <= 9; ++i) lst.push_back(i);
printContainer(lst, "容器lst中的元素:"); // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
// *********************** find ***********************
// 输出lst中两个4之间的所有数据
std::list<int>::iterator pos1 = find(lst.begin(), lst.end(), 4);
std::list<int>::iterator pos2 = find(++pos1, lst.end(), 4);
--pos1; ++pos2;
for (std::list<int>::iterator iter = pos1; iter != pos2; ++iter) std::cout << *iter << " ";
std::cout << std::endl; // 4 5 6 7 8 9 0 1 2 3 4
// *********************** find_if ***********************
std::vector<int> vt(++lst.begin(), --lst.end());
for (std::vector<int>::const_iterator iter = vt.begin(); iter != vt.end(); ++iter) std::cout << *iter << " ";
std::cout << std::endl; // 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8
std::vector<int>::iterator pos = find_if(vt.begin(), vt.end(), std::bind2nd(std::greater<int>(), 3));
std::cout << "容器vt中第一个大于3的数为:" << *pos << std::endl;
pos = find_if(vt.begin(), vt.end(), std::not1(std::bind2nd(std::modulus<int>(), 3)));
std::cout << "容器vt中第一个能被3整除的数为:" << *pos << std::endl;
std::set<int> st(vt.begin(), vt.end()); // set容器适配器(或关联容器),不允许元素重复,自动排序。
printContainer(st, "容器st中的元素:"); // 0 1 2 3 4 5 6 7 8 9
std::cout << *find(st.begin(), st.end(), 4) << "在容器st中。\n"; // 对所有容器通用find方法,线性查找,速度慢
std::cout << *st.find(5) << "在容器st中。\n"; // 关联容器内部find方法,二分查找,速度快
std::string str("Hello C++ World");
std::cout << str << std::endl;
std::string::size_type p = str.find("C++");
if (p != std::string::npos)
std::cout << "找到C++,开始字符为:" << str[p] << " ,下标为:" << p << std::endl;
else
std::cout << "没有找到!" << std::endl;
// *********************** search_n ***********************
std::deque<int> dq(vt.begin(), vt.end());
dq.push_back(3); dq.push_back(3); dq.push_back(1);
sort(dq.begin(), dq.end());
printContainer(dq, "容器dq中的元素:"); // 0 1 1 1 2 2 3 3 3 3 4 4 5 5 6 6 7 7 8 8 9
std::deque<int>::iterator pos3 = search_n(dq.begin(), dq.end(), 3, 1);
if (pos3 != dq.end())
std::cout << "找到连续的3个1,起始下标为:" << std::distance(dq.begin(), pos3) << std::endl;
pos3 = search_n(dq.begin(), dq.end(), 5, 6, std::greater<int>()); // 注意,此处写法不符合STL规范,历史原因造成的,记住即可;
//pos3 = search_n_if(dq.begin(), dq.end(), 5, std::bind2nd(std::greater<int>(), 6)); //**这种写法更符合规范,但历史原因,是错误的
if(pos3 != dq.end())
std::cout << "找到连续的5个大于6的数,起始下标为:" << pos3 - dq.begin() << std::endl; // pos3 - dq.begin()这种方式仅适用于可通过下标索引访问的容器
// *********************** search ***********************
printContainer(lst, "now, 容器lst中的元素:"); // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
printContainer(st, "now, 容器st中的元素:"); // 0 1 2 3 4 5 6 7 8 9
printContainer(dq, "now, 容器dq中的元素:"); // 0 1 1 1 2 2 3 3 3 3 4 4 5 5 6 6 7 7 8 8 9
std::list<int>::iterator poslist = search(lst.begin(), lst.end(), st.begin(), st.end());
if (poslist != lst.end())
std::cout << "容器st区间在lst区间中,起始位置位:" << std::distance(lst.begin(), poslist) << std::endl;
std::deque<int>::iterator posdeque = search(dq.begin(), dq.end(), st.begin(), st.end());
if (posdeque != dq.end())
std::cout << "容器st区间在lst区间中,起始位置位:" << std::distance(dq.begin(), posdeque) << std::endl;
else
std::cout << "容器st区间不在在dq区间\n";
bool flags[] = { true, false, true };
//或者:std::vector<bool> flags = {true, false, true}; 下面flag, flag+3改为flag.begin(), flag.end()
std::set<int>::iterator posset = search(st.begin(), st.end(), flags, flags + 3, checkEven);
if (posset != st.end())
std::cout << "在容器st中存在 偶数-奇数-偶数(true,false,true) 的序列,起始位置为:" << std::distance(st.begin(), posset) << std::endl; // 不能使用这种方式:posset - st.begin()
std::vector<bool> vflag = { true, true, false, false };
posdeque = search(dq.begin(), dq.end(), vflag.begin(), vflag.end(), checkEven);
if (posdeque != dq.end())
std::cout << "在容器dq中存在 偶数-偶数-奇数-奇数(true,true,false,false) 的序列,起始位置为:" << posdeque - dq.begin() << std::endl; // <==>std::distance(dq.begin(), posdeque)
// *********************** find_end (与search对应,找满足条件的最后一个) ***********************
poslist = find_end(lst.begin(), lst.end(), st.begin(), st.end());
if (poslist != lst.end())
std::cout << "容器st区间在lst区间中,起始位置位:" << std::distance(lst.begin(), poslist) << std::endl;
posdeque = find_end(dq.begin(), dq.end(), st.begin(), st.end());
if (posdeque != dq.end())
std::cout << "容器st区间在lst区间中,起始位置位:" << std::distance(dq.begin(), posdeque) << std::endl;
else
std::cout << "容器st区间不在在dq区间\n";
// *********************** find_first_of ***********************
printContainer(st, "now, 容器st中的元素:"); // 0 1 2 3 4 5 6 7 8 9
std::vector<int> find_list = { 3,5,7 };
std::set<int>::iterator spos = find_first_of(st.begin(), st.end(), find_list.begin(), find_list.end());
if (spos != st.end())
std::cout << "find_list容器中存在某元素也在st容器中,下标为:" << distance(st.begin(), spos) << std::endl;
std::set<int>::reverse_iterator rspos = find_first_of(st.rbegin(), st.rend(), find_list.begin(), find_list.end()); // 逆向查找需要使用逆向迭代器reverse_iterator
if (spos != st.end())
std::cout << "find_list容器中存在某元素也在st容器中,下标为:" << distance(st.begin(), rspos.base()) - 1 << std::endl; // 使用distance方法时,需要经rspos转化为正向迭代器,由于转变过程中的机制,需要再减1
// 对于string类型,有find_first_of 和 find_last_of两种迭代器,而其它容器只有find_first_of一种方法,但可通过逆向迭代器实现find_last_of的功能。
// string类型的find_first_of 请参考:https://blog.youkuaiyun.com/sunqin_csdn/article/details/85028480
// *********************** adjacent_find ***********************
printContainer(dq, "now, 容器dq中的元素:"); // 0 1 1 1 2 2 3 3 3 3 4 4 5 5 6 6 7 7 8 8 9
std::deque<int>::iterator dpos = adjacent_find(dq.begin(), dq.end());
if (dpos != dq.end())
std::cout << "找到dq容器中第一组连续两个相等的元素,下标为:" << dpos - dq.begin() << std::endl;
std::deque<int>::reverse_iterator rdpos = adjacent_find(dq.rbegin(), dq.rend());
if (rdpos != dq.rend())
std::cout << "找到dq容器中最后一组连续两个相等的元素,下标为:" << distance(dq.begin(), rdpos.base()) - 1 << std::endl;
dpos = adjacent_find(dq.begin(), dq.end(), myAdjacent);
if (dpos != dq.end())
std::cout << "找到dq容器满足adjacent逻辑的一组元素,下标为:" << distance(dq.begin(), dpos) << std::endl;
// ********** 已序区间算法:binary_search, includes, lower_bound, upper_bound, equal_bound
// *********************** binary_search ***********************
printContainer(dq, "now, 容器dq中的元素:"); // 0 1 1 1 2 2 3 3 3 3 4 4 5 5 6 6 7 7 8 8 9
if(binary_search(dq.begin(), dq.end(), 5)) // binary_search方法只能查找元素是否存在,无法得到找到的元素的位置
std::cout << "元素5在容器dq中\n";
// *********************** includes ***********************
if (includes(dq.begin(), dq.end(), find_list.begin(), find_list.end())) // includes方法返回是否找到,find_list需要有序,只有其中的所有元素都被找到,才返回true;
std::cout << "容器find_list中的所有元素都存在于dq容器中。\n";
// *********************** lower_bound ***********************
dpos = lower_bound(dq.begin(), dq.end(), 3);
if (dpos != dq.end())
std::cout << "容器dq中第一个3的位置为:" << distance(dq.begin(), dpos) << std::endl;
// *********************** upper_bound ***********************
dpos = upper_bound(dq.begin(), dq.end(), 3);
if (dpos != dq.end())
std::cout << "容器dq中最后一个3的下一个位置为:" << distance(dq.begin(), dpos) << std::endl;
// *********************** equal_bound *********************** // 等效于lower_bound和upper_bound
std::pair<std::deque<int>::iterator, std::deque<int>::iterator> dpos12;
dpos12 = equal_range(dq.begin(), dq.end(), 3);
std::cout << "容器dq中第一个3的位置为:" << distance(dq.begin(), dpos12.first) << std::endl;
std::cout << "容器dq中最后一个3的下一个位置为:" << distance(dq.begin(), dpos12.second) << std::endl;
// 对于关联式容器,有其内部的成员函数可用,速度更快。
std::multiset<int> mst(dq.begin(), dq.end());
printContainer(mst, "now, 容器mst中的元素:"); // 0 1 1 1 2 2 3 3 3 3 4 4 5 5 6 6 7 7 8 8 9
std::multiset<int>::iterator mpos = mst.lower_bound(5);
std::cout << "容器mst中第一个5的位置为:" << distance(mst.begin(), mpos) << std::endl;
//system("pause");
return 0;
}
2.4 for_each方法
#include<iostream>
#include<vector>
#include<algorithm>
template <typename Container>
void printContainer(const Container& con, std::string str)
{
std::cout << str.c_str();
for (Container::const_iterator it = con.begin(); it != con.end(); ++it)
std::cout << *it << " ";
std::cout << std::endl;
}
void printContent(int elem)
{
std::cout << elem << " ";
}
template <typename T>
class addValue
{
private:
T the_value;
public:
addValue(const T& v):the_value(v) {}
void operator() (T& elem) const
{
elem += the_value;
}
};
class getMeanValue
{
private:
long sum;
long count;
public:
getMeanValue() :sum(0), count(0) {}
void operator() (int elem)
{
sum += elem;
count++;
}
double value()
{
return static_cast<double>(sum) / static_cast<double>(count);
}
operator double()
{
return static_cast<double>(sum) / static_cast<double>(count);
}
};
int main()
{
std::vector<int> vt = { 1,2,3,4,5,6,7,8,9 };
printContainer(vt, "容器vt中的元素为:"); // for_each(vt.begin(), vt.end(), printContent); std::cout << std::endl;
for_each(vt.begin(), vt.end(), addValue<int>(*(--vt.end())));
printContainer(vt, "now,容器vt中的元素为:");
for_each(vt.begin(), vt.end(), addValue<int>(10));
printContainer(vt, "now,容器vt中的元素为:");
getMeanValue gmv = for_each(vt.begin(), vt.end(), getMeanValue()); // 类getMeanValue的返回值其对象,通过相应的函数得到平均值;
std::cout << "now,容器均值为:" << gmv.value() << std::endl;
double mv = for_each(vt.begin(), vt.end(), getMeanValue()); // 其返回值仍然为getMeanValue的对象,但被operator double()进行强制类型转换为double类型,故可以用double类型变量来接受;
std::cout << "now,容器均值为:" << mv << std::endl;
//system("pause");
return 0;
}
2.5 transform 方法
transform(b1, e1, b2, op),将源区间b1和e1之间的元素经过op操作再插入到目标b2区间中。
transform(b1,e1,b2,b3,op),将源区间b1和e1区间的元素和b2间的元素进行op操作后插入到目标b3区间中。
for_each(), 其谓词传递引用,无返回值,速度快,但不灵活。
transform(),其谓词传递拷贝,有返回值,速度慢,非常灵活。
注意:
- 如果目标与源相同,则transform()和for_each()一样。
- 如果想以某值替代符合规则的元素,应使用replace()算法。
#include<iostream>
#include<vector>
#include<list>
#include<algorithm>
#include<functional>
#include<iterator>
template <typename Container>
void printContainer(const Container& con, std::string str)
{
std::cout << str.c_str();
for (Container::const_iterator it = con.begin(); it != con.end(); ++it)
{
std::cout << *it << " ";
}
std::cout << std::endl;
}
void mySqrt(int& elem) // 充当for_each的谓词,必须要是引用,修改elem相当于直接修改传入容器元素的值;由于传递应用,故速度很快
{
elem = sqrt(elem);
}
int mySquare(int elem) // 充当transform的谓词,传递的不是引用,而是其拷贝,有返回值,故速度较慢
{
return elem * elem;
}
int main()
{
// ****************** transform(b1, e1, b2, op) ******************
std::vector<int> vt = { 1,2,3,4,5,6,7,8,9 };
printContainer(vt, "now, 容器vt中的内容为:"); // 1 2 3 4 5 6 7 8 9
transform(vt.begin(), vt.end(), vt.begin(), std::negate<int>()); // transform函数在<algorithm>头文件中,negate函数在<functional>头文件中
printContainer(vt, "now, 容器vt中的内容为:"); // -1 -2 -3 -4 -5 -6 -7 -8 -9
std::list<int> lst;
transform(vt.begin(), vt.end(), back_inserter(lst), std::bind2nd(std::multiplies<int>(), 10)); //使用back_inserter方法, ×10后的结果插入到lst的后面
printContainer(lst, "now, 容器lst中的内容为:"); // -10 -20 -30 -40 -50 -60 -70 -80 -90
transform(lst.begin(), lst.end(), std::ostream_iterator<int>(std::cout, " "), std::negate<int>()); // negate取负操作,将结果指定到输出流中输出,源区间lst容器中的值不变
printContainer(lst, "\nnow, 容器lst中的内容为:"); // -10 -20 -30 -40 -50 -60 -70 -80 -90
// ****************** transform(b1, e1, b2, b3, op) ******************
printContainer(vt, "now, 容器vt中的内容为:"); // -1 -2 -3 -4 -5 -6 -7 -8 -9
transform(vt.begin(), vt.end(), vt.begin(), vt.begin(), std::multiplies<int>()); // 将容器vt中数据自乘后放回到源容器;
printContainer(vt, "now, 容器vt中的内容为:"); // 1 4 9 16 25 36 49 64 81
transform(vt.begin(), vt.end(), vt.rbegin(), back_inserter(lst), std::plus<int>()); // 使用back_inserter方法, 相加后的结果插入到lst的后面,注意第三个参数为逆向迭代器
printContainer(lst, "now, 容器lst中的内容为:"); // -10 -20 -30 -40 -50 -60 -70 -80 -90 82 68 58 52 50 52 58 68 82
transform(vt.begin(), vt.end(), lst.begin(), std::ostream_iterator<int>(std::cout, " "), std::minus<int>()); // 将vt中元素减去lst中元素的结果输出;vt和lst容器中的元素值无变化
printContainer(vt, "now, 容器vt中的内容为:"); // 1 4 9 16 25 36 49 64 81
printContainer(lst, "now, 容器lst中的内容为:"); // -10 -20 -30 -40 -50 -60 -70 -80 -90 82 68 58 52 50 52 58 68 82
// ***** for_each 与 transform *****
std::cout << "-----------------------------------\n";
printContainer(vt, "now, 容器vt中的内容为:"); // 1 4 9 16 25 36 49 64 81
for_each(vt.begin(), vt.end(), mySqrt);
printContainer(vt, "now, 容器vt中的内容为:"); // 1 2 3 4 5 6 7 8 9
transform(vt.begin(), vt.end(), vt.begin(), mySquare); // 1 4 9 16 25 36 49 64 81
printContainer(vt, "now, 容器vt中的内容为:");
system("pause");
return 0;
}
2.6 区间比较算法
算法 | 解释 |
---|---|
equal(b, e, b2); | 若b-e区间的值和b2开始的区间的值全相等,则为true,否则为false |
equal(b, e, b2, p); | |
mismatch(b, e, b2); | 查找b-e区间的值和b2开始的区间的第一个不相等值,返回值为指向各自区间对应不相等的元素的迭代器;若 == container.end(), 说明这两个区间相等。 |
mismatch(b, e, b2, p); | |
lexicographical_compare(b, e, b2, e2); | 若b-e区间的元素值小于b2-e2区间的元素值,则为true,否则为false。区间比较大小的逻辑通字符串的比较。 |
lexicographical_compare(b, e, b2, e2, p); |
#include<iostream>
#include<vector>
#include<list>
#include<algorithm>
using std::endl;
using std::cout;
using std::vector;
template <typename Container>
void printContainer(const Container& con, std::string str)
{
std::cout << "-----------------------------------\n" << str.c_str();
for (Container::const_iterator it = con.begin(); it != con.end(); ++it)
std::cout << *it << " ";
std::cout << "\n";
}
bool evenOrOdd(int elem1, int elem2)
{
return elem1 % 2 == elem2 % 2;
}
bool myLess(std::list<int> lst1, std::list<int> lst2)
{
return lexicographical_compare(lst1.begin(), lst1.end(), lst2.begin(), lst2.end());
}
void myPrint(std::list<int> lst)
{
for (std::list<int>::iterator it = lst.begin(); it != lst.end(); ++it)
cout << *it << " ";
cout << endl;
}
int main()
{
// ********** equal **********
vector<int> vt = { 1,2,3,4,5,6,7,8,9 };
vector<int> vt2(vt.rbegin(), vt.rend()); // 9 8 7 6 5 4 3 2 1
printContainer(vt, "now, 容器vt中内容为:");
printContainer(vt2, "now, 容器vt2中内容为:");
if (equal(vt.begin(), vt.end(), vt2.rbegin())) // if (equal(vt.rbegin(), vt.rend(), vt2.begin()))
cout << "相等\n"; // equal比较,只有当比较的区间的所有元素全部相等时才为true
if (equal(vt.begin(), vt.end(), vt2.rbegin(), evenOrOdd))
cout << "奇偶顺序相同\n";
reverse(vt2.begin(), vt2.end());
vt2.push_back(0);
printContainer(vt2, "now, 容器vt2中内容为:"); // 1 2 3 4 5 6 7 8 9 0
if (!equal(vt.begin(), vt.end(), vt2.rbegin())) // if (equal(vt.rbegin(), vt.rend(), vt2.begin()))
cout << "不相等\n"; // equal比较,只有当比较的区间的所有元素全部相等时才为true
// ********** mismatch ********** // 找两个容器中第一个不相等的元素的位置
std::list<int> lst(vt2.begin(), vt2.end());
std::pair<std::vector<int>::iterator, std::list<int>::iterator> pit;
pit = mismatch(vt.begin(), vt.end(), lst.begin());
if (pit.first == vt.begin())
cout << "容器vt和lst中没有不匹配的数。\n"; // 但不能说明vt和lst相等
vt[vt.size() / 2 + 1] = 0;
printContainer(vt, "now, 容器vt中内容为:"); // 1 2 3 4 5 0 7 8 9
printContainer(lst, "now, 容器lst中内容为:"); // 1 2 3 4 5 6 7 8 9 0
pit = mismatch(vt.begin(), vt.end(), lst.begin());
cout << "first mismatch: " << *pit.first << " " << *pit.second << endl;
lst.pop_back();
reverse(lst.begin(), lst.end());
printContainer(lst, "now, 容器lst中内容为:"); // 9 8 7 6 5 4 3 2 1
pit = mismatch(vt.begin(), vt.end(), lst.begin(), std::less_equal<int>()); // 找到vt容器中第一个大于lst的对应位置元素
if(pit.first != vt.end())
cout << "first greater: " << *pit.first << " " << *pit.second << endl;
// ********** lexicographical_compare() ********** // 比较两个容器区间的大小,若第一个区间小于第二个区间,则返回true
std::vector<std::list<int> > vlst = { {1,2,3,4,5}, {1,2,3,4,5,0}, {1,2,3,4,5, 2}, {1,2,3,4,5,2,0}, {1,2,3,4,5,7} };
sort(vlst.begin(), vlst.end(), myLess);
for_each(vlst.begin(), vlst.end(), myPrint);
std::list<int> lst2 = {1,2,3,4,5}, lst3 = {1,2,3,4,5};
cout << lexicographical_compare(lst2.begin(), lst2.end(), lst3.begin(), lst3.end()) << endl; // 0
//system("pause");
return 0;
}
2.7 复制元素
copy()与copy_backward()
注意:
1. 没有copy_if()算法,可使用remove_copy_if()算法。
2. 复制过程中要逆序元素次序,可使用reverse_copy()算法。
3. 把容器内所有元素赋值给另一个元素,要使用赋值操作或容器的assign()成员函数
4. 复制过程中删除某些元素,使用remove_copy()和remove_copy_if()算法。
5. 复制中改变元素,使用transform()或replace_copy()算法。
#include<iostream>
#include<list>
#include<vector>
#include<algorithm>
#include<iterator>
using std::cout;
using std::endl;
using std::vector;
using std::list;
template <typename Container>
void printContainer(const Container& con, std::string str)
{
std::cout << "-----------------------------------\n" << str.c_str();
for (Container::const_iterator it = con.begin(); it != con.end(); ++it)
std::cout << *it << " ";
std::cout << "\n";
}
int main()
{
// ********** copy ********** // copy时需要注意目标空间的大小要足够大
vector<int> vt = { 1,2,3,4,5 };
list<int> lst = { 0,1,2 };
//copy(vt.begin(), vt.end(), lst.begin()); // 报错!目标容器的空间不够会报错
copy(vt.begin(), vt.end(), back_inserter(lst)); //对于目标容器的空间不够,可以使用back_inserter方法
printContainer(vt, "now, 容器vt中内容为:"); // 1 2 3 4 5
printContainer(lst, "now, 容器lst中内容为:"); // 0 1 2 1 2 3 4 5
vector<int> vt2(vt.size() * 4);
printContainer(vt2, "now, 容器vt2中内容为:"); // 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
copy(vt.begin(), vt.end(), vt2.begin()); // 结果:1 2 3 4 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
copy(vt.begin(), vt.end(), vt2.begin()); // 只会copy到指定的位置 结果:1 2 3 4 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
printContainer(vt2, "now, 容器vt2中内容为:"); // 1 2 3 4 5 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5
//copy(vt.begin(), vt.end(), vt2.end()); 报错
copy(vt.begin(), vt.end(), vt2.begin() + vt.size());
printContainer(vt2, "now, 容器vt2中内容为:"); // 1 2 3 4 5 1 2 3 4 5 0 0 0 0 0 0 0 0 0 0
// ********** copy_backward ********** copy_backward 从后往前拷贝
copy_backward(vt.begin(), vt.end(), vt2.end());
printContainer(vt2, "now, 容器vt2中内容为:"); // 1 2 3 4 5 1 2 3 4 5 0 0 0 0 0 1 2 3 4 5
copy(vt.rbegin(), vt.rend(), vt2.end() - vt.size()); // 使用逆序迭代器,反向拷贝
printContainer(vt2, "now, 容器vt2中内容为:"); // 1 2 3 4 5 1 2 3 4 5 0 0 0 0 0 5 4 3 2 1
reverse_copy(vt.begin(), vt.end(), vt2.end() - vt.size()); // ** 效果与上面使用逆向迭代器相同,反向copy
printContainer(vt2, "now, 容器vt2中内容为:"); // 1 2 3 4 5 1 2 3 4 5 0 0 0 0 0 5 4 3 2 1
reverse_copy(vt.rbegin(), vt.rend(), vt2.end() - vt.size()); //两次反向,相当于顺序copy
printContainer(vt2, "now, 容器vt2中内容为:"); // 1 2 3 4 5 1 2 3 4 5 0 0 0 0 0 1 2 3 4 5
copy(vt2.begin(), vt2.end(), std::ostream_iterator<int>(cout, " ")); // 将区间中元素copy到输出流,即输出;
std::cout << std::endl;
//system("pause");
return 0;
}
2.8 交换算法
swap_range(b, e, b2);交换b到e区间的元素与b2开始的区间元素(交换相同个数)返回值为指向b2容器的第一个未交换的元素。
对于相同类型的容器,且交换两容器的所有元素(不管个数是否相同,全部交换),使用容器内部swap成员函数交换更快(实际交换容器内部的迭代器)
#include<iostream>
#include<vector>
#include<deque>
#include<algorithm>
using std::cout;
using std::endl;
using std::vector;
using std::deque;
template <typename Container>
void printContainer(const Container& con, std::string str)
{
std::cout << "-----------------------------------\n" << str.c_str();
for (Container::const_iterator it = con.begin(); it != con.end(); ++it)
std::cout << *it << " ";
std::cout << "\n";
}
int main()
{
// ********** swap_ranges **********
vector<int> vt = { 1,2,3,4,5 };
deque<int> dq = { 9,8,7,6,5,4,3,2,1,0 };
printContainer(vt, "now, 容器vt中内容为:"); // 1 2 3 4 5
printContainer(dq, "now, 容器dq中内容为:"); // 10,9,8,7,6,5,4,3,2,1
deque<int>::iterator pos = swap_ranges(vt.begin(), vt.end(), dq.begin());
printContainer(vt, "after swap_ranges, 容器vt中内容为:"); // 10 9 8 7 6
printContainer(dq, "after swap_ranges, 容器dq中内容为:"); // 1 2 3 4 5 5 4 3 2 1
if (pos != dq.end())
cout << "容器dq中第一个没有交换的数为:" << *pos << endl;
swap_ranges(dq.begin(), dq.begin() + 4, dq.rbegin());
printContainer(dq, "after self swap_ranges, 容器dq中内容为:"); // 0 1 2 3 5 4 4 3 2 1
// ********** swap ********** // 对于相同类型的容器,交换所有元素,用swap成员函数更合适(交换内部指针,速度更快)
vector<int> vt2(dq.begin(), dq.end());
printContainer(vt, "now, 容器vt中内容为:"); // 9 8 7 6 5
printContainer(vt2, "now, 容器vt2中内容为:"); // 0 1 2 3 5 4 4 3 2 1
vt2.swap(vt); // vt.swap(vt2);
printContainer(vt, "after swap, 容器vt中内容为:"); // 0 1 2 3 5 4 4 3 2 1
printContainer(vt2, "after swap, 容器vt2中内容为:"); // 9 8 7 6 5
system("pause");
return 0;
}
2.9 填充新值
fill(b, e, v)
fill(b, n, v)
generate(b, e, p)
generate_n(b, n, p)
#include<iostream>
#include<vector>
#include<list>
#include<string>
#include<algorithm>
#include<iterator>
using std::cout;
using std::endl;
using std::vector;
using std::string;
using std::list;
template <typename Container>
void printContainer(const Container& con, std::string str)
{
std::cout << "-----------------------------------\n" << str.c_str();
for (Container::const_iterator it = con.begin(); it != con.end(); ++it)
std::cout << *it << " ";
std::cout << "\n";
}
int main()
{
// ********** fill & fill_n ********** // 填充新常量值
vector<string> vts = { "hello " , "world ", "C++ ", "Welcome" };
printContainer(vts, "now, 容器vts中的元素:"); // hello world C++ Welcome
fill(vts.begin(), vts.end(), "Hello ");
printContainer(vts, "after fill, 容器vts中的元素:"); // Hello Hello Hello Hello
// fill_n(vts.begin(), 5, "World "); vts容器中只有4个元素,fill了5个,报错;fill_n函数需要目标容器有足够的容量来fill
fill_n(back_inserter(vts), 5, "World "); // 使用back_inserter函数,直接在末尾插入,不需要提前分配内存。
printContainer(vts, "after fill, 容器vts中的元素:"); // Hello Hello Hello Hello World World World World World
list<string> lsts;
fill_n(back_inserter(lsts), 10, "C++"); // C++ C++ C++ C++ C++ C++ C++ C++ C++ C++
printContainer(lsts, "after fill_n, 容器lsts中的元素:");
fill_n(lsts.begin(), lsts.size() - 4, "Primer"); // Primer Primer Primer Primer Primer Primer C++ C++ C++ C++
printContainer(lsts, "after fill_n, 容器lsts中的元素:");
fill_n(std::ostream_iterator<float>(cout, " "), 5, 12.3); cout << endl; // 12.3 12.3 12.3 12.3 12.3
// ********** generate_n ********** // 填充新的可变值
cout << "**************************************\n";
list<int> lsti;
generate_n(back_inserter(lsti), 5, rand);
printContainer(lsti, "now, 容器lsti中内容为:");
generate(lsti.begin(), lsti.end(), rand);
printContainer(lsti, "now, 容器lsti中内容为:");
//system("pause");
return 0;
}
2.10 替换算法
replace(b, e, v1, v2); 将区间b-e的所有元素中的所有的值v1替换成v2
replace_if(b, e, op, v); 将区间b-e的所有元素中的所有满足op谓词的元素替换成v2
replace_copy(b1, e1, b2, v1, v2);
replace_copy_if(b1, e1, b2, p, v);
#include<iostream>
#include<list>
#include<algorithm>
#include<functional> // bind2nd 函数
#include<iterator>
using std::endl;
using std::cout;
using std::list;
template <typename Container>
void printContainer(const Container& con, std::string str)
{
std::cout << "-----------------------------------\n" << str.c_str();
for (Container::const_iterator it = con.begin(); it != con.end(); ++it)
std::cout << *it << " ";
std::cout << "\n";
}
int main()
{
// ********** replace **********
list<int> lst = { 1,3,5,7,1,2,3,4,5,6,6,6};
printContainer(lst, "now, 容器lst中的元素:"); // 1,3,5,7,1,2,3,4,5,6,6,6
replace(lst.begin(), lst.end(), 6, 9); // 将6全部替换成9
printContainer(lst, "after replace, 容器lst中的元素:"); // 1,3,5,7,1,2,3,4,5,9,9,9
replace_if(lst.begin(), lst.end(), std::bind2nd(std::less_equal<int>(), 3), 0); // 将小于等于3的数全部替换成0;
printContainer(lst, "after replace_if, 容器lst中的元素:"); // 0 0 5 7 0 0 0 4 5 9 9 9
// ********** replace_copy **********
replace_copy(lst.begin(), lst.end(), std::ostream_iterator<int>(cout, " "), 5, 50); // 0 0 50 7 0 0 0 4 50 9 9 9
cout << endl; // 将5替换为50, replace_copy, 在replace之后再copy到输出流; 但lst中的元素无任何变化
replace_copy_if(lst.begin(), lst.end(), std::ostream_iterator<int>(cout, " "), std::bind2nd(std::modulus<int>(), 2), -1);
cout << endl; // 上面操作将所有奇数替换成 -1, // 0 0 -1 -1 0 0 0 4 -1 -1 -1 -1
printContainer(lst, "now, 容器lst中的元素:"); // 0 0 5 7 0 0 0 4 5 9 9 9 // replace_copy 以后,源容器中的元素值不变
//system("pause");
return 0;
}
2.11 删除算法
remove();
remove_if();
remove_copy();
remove_copy_if();
unique(); 删除连续重复的元素
unique_copy();
注意:remove()和remove_if()并不是真正的删除,而是把删除位置后面的元素赋值给前面的元素,容器中元素的个数并未减少。
#include<iostream>
#include<list>
#include<deque>
#include<algorithm>
#include<functional>
#include<iterator>
using std::endl;
using std::cout;
using std::list;
template <typename Container>
void printContainer(const Container& con, std::string str)
{
std::cout << "-----------------------------------\n" << str.c_str();
for (Container::const_iterator it = con.begin(); it != con.end(); ++it)
std::cout << *it << " ";
std::cout << "\n";
}
bool differenceOne(int elem1, int elem2)
{
return abs(elem1 - elem2) == 1;
}
int main()
{
// ************ remove 和 remove_if *************
list<int> lst;
for (int i = 0; i <= 5; ++i) {
lst.push_front(i);
lst.push_back(i);
}
printContainer(lst, "now, 容器lst中的内容为:"); // 5 4 3 2 1 0 0 1 2 3 4 5
list<int>::iterator it = remove(lst.begin(), lst.end(), 3); // remove方法,将lst中3都删除,删除的位置有其后面的元素补上,返回值为逻辑终点
printContainer(lst, "now, 容器lst中的内容为:"); // 5 4 2 1 0 0 1 2 4 5 4 5
cout << "删除了" << distance(it, lst.end()) << "个3\n";
lst.erase(it, lst.end());
printContainer(lst, "now, 容器lst中的内容为:"); // 5 4 2 1 0 0 1 2 4 5
lst.erase(remove_if(lst.begin(), lst.end(), std::bind2nd(std::greater<int>(), 3)), lst.end()); // 删除大于3的数
printContainer(lst, "now, 容器lst中的内容为:"); // 2 1 0 0 1 2
// ************ remove_copy 和 remove_copy_if *************
std::deque<int> dq = {1,2,3,4,5,6,7,8,9,1,3,5,7,9};
remove_copy(dq.begin(), dq.end(), std::ostream_iterator<int>(cout, " "), 1); // 删除1后,将剩余的数据送到输出流
cout << endl; // 2 3 4 5 6 7 8 9 3 5 7 9
remove_copy_if(dq.begin(), dq.end(), std::ostream_iterator<int>(cout, " "), std::bind2nd(std::less_equal<int>(), 3));
cout << endl; // 删除<=3的数后,将剩余的数据送到输出流 // 4 5 6 7 8 9 5 7 9
// ************ unique 和 unique_copy *************
lst.push_back(2); lst.push_front(2);
printContainer(lst, "now, 容器lst中的内容为:"); // 2 2 1 0 0 1 2 2
it = unique(lst.begin(), lst.end());
printContainer(lst, "now, 容器lst中的内容为:"); // 2 1 0 1 2 1 2 2
for (list<int>::iterator iter = lst.begin(); iter != it; ++iter)
cout << *iter << " ";
cout << endl; // 2 1 0 1 2
lst.insert(lst.end(), dq.begin(), dq.end());
printContainer(lst, "now, 容器lst中的内容为:"); // 2 1 0 1 2 1 2 2 1 2 3 4 5 6 7 8 9 1 3 5 7 9
it = unique(lst.begin(), lst.end(), std::greater<int>()); // 若容器中该元素的值小于前一位置的元素值,则删除该元素
printContainer(lst, "now, 容器lst中的内容为:"); // 2 2 2 2 2 3 4 5 6 7 8 9 9 6 7 8 9 1 3 5 7 9
for (list<int>::iterator iter = lst.begin(); iter != it; ++iter)
cout << *iter << " ";
cout << endl; // 2 2 2 2 2 3 4 5 6 7 8 9 9
lst.push_back(9); lst.push_back(9);
printContainer(lst, "now, 容器lst中的内容为:"); // 2 2 2 2 2 3 4 5 6 7 8 9 9 6 7 8 9 1 3 5 7 9
unique_copy(lst.begin(), lst.end(), std::ostream_iterator<int>(cout, " "));// 2 3 4 5 6 7 8 9 6 7 8 9 1 3 5 7 9
cout << endl; // 将操作的结果送到输出流,源容器中的数据不变
unique_copy(lst.begin(), lst.end(), std::ostream_iterator<int>(cout, " "), differenceOne); // 删除连续差值为1的数,注意,删除该元素后,其后的元素与之前的元素比较
cout << endl; // 2 2 2 2 2 4 6 8 6 8 1 3 5 7 9
//system("pause");
return 0;
}
2.12 逆转和旋转
reverse(b, e); 将b-e区间的元素逆转
reverse_copy();
rotate(b, be, e); 将[b,be) 和 [be, e)之间的元素旋转
rotate_copy();
#include<iostream>
#include<set>
#include<vector>
#include<algorithm>
#include<functional>
#include<iterator>
using std::endl;
using std::cout;
using std::set;
using std::vector;
template <typename Container>
void printContainer(const Container& con, std::string str)
{
std::cout << "-----------------------------------\n" << str.c_str();
for (Container::const_iterator it = con.begin(); it != con.end(); ++it)
std::cout << *it << " ";
std::cout << "\n";
}
int main()
{
// ********** reverse **********
vector<int> vt = { 1,2,3,4,5,6,7,8,9 };
printContainer(vt, "now, 容器vt中的内容为;"); // 1,2,3,4,5,6,7,8,9
reverse(++vt.begin(), --vt.end());
printContainer(vt, "now, 容器vt中的内容为;"); // 1 8 7 6 5 4 3 2 9
reverse_copy(vt.begin(), vt.end(), std::ostream_iterator<int>(cout, " "));
cout << endl; // 9 2 3 4 5 6 7 8 1
// ********** rotate **********
printContainer(vt, "now, 容器vt中的内容为;"); // 1 8 7 6 5 4 3 2 9
rotate(vt.begin(), vt.begin() + vt.size() / 2, vt.end()); // rotate(it1, it2, it3),将区间[it1-it2)与[it2-it3)之间的元素互换
printContainer(vt, "now, 容器vt中的内容为;"); // 5 4 3 2 9 1 8 7 6
rotate(vt.begin(), find(vt.begin(),vt.end(), 9), vt.end());
printContainer(vt, "now, 容器vt中的内容为;"); // 9 1 8 7 6 5 4 3 2
// ********** rotate **********
set<int> st(vt.begin(), vt.end());
printContainer(st, "now, 容器st中的内容为;"); // 1,2,3,4,5,6,7,8,9
set<int>::iterator it = st.end();
advance(it, -(int)st.size() / 2); // 一般的随机迭代器可以直接:it = it - st.size() / 2; 但对于set的迭代器(为双向迭代器,内部为二叉树结构)中不能用这种方式,
rotate_copy(st.begin(), it, st.end(), std::ostream_iterator<int>(cout, " ")); // rotate_copy 将旋转的结果copy到输出流
cout << endl;
printContainer(st, "now, 容器st中的内容为;"); // 1,2,3,4,5,6,7,8,9
rotate_copy(st.begin(), find(st.begin(), st.end(), 5), st.end(), std::ostream_iterator<int>(cout, " ")); // rotate_copy 将旋转的结果copy到输出流
cout << endl;
//system("pause");
return 0;
}
2.13 排列组合算法
next_permutation(); 从小到大排序输出下一个排列
prev_permutation(); 从大到小排序输出下一个排列
#include<iostream>
#include<vector>
#include<algorithm>
using std::endl;
using std::cout;
using std::vector;
int main()
{
// ********** next_permutation **********
vector<int> vt = {1,2,3,4};
for (vector<int>::iterator it = vt.begin(); it != vt.end(); ++it)
cout << *it << " ";
cout << endl;
while (next_permutation(vt.begin(), vt.end()))
{
for (vector<int>::iterator it = vt.begin(); it != vt.end(); ++it)
cout << *it << " ";
cout << endl;
}
cout << "-**************************-\n";
vector<int> vt2 = { 1,4,3,2 };
for (vector<int>::iterator it = vt2.begin(); it != vt2.end(); ++it)
cout << *it << " ";
cout << endl;
while (next_permutation(vt2.begin(), vt2.end())) // next_permutation, 从大到小排序
{
for (vector<int>::iterator it = vt2.begin(); it != vt2.end(); ++it)
cout << *it << " ";
cout << endl;
}
cout << "--------------------------\n";
vt2 = { 1,4,3,2 };
for (vector<int>::iterator it = vt2.begin(); it != vt2.end(); ++it)
cout << *it << " ";
cout << endl;
while (prev_permutation(vt2.begin(), vt2.end())) // next_permutation, 从小到大排序
{
for (vector<int>::iterator it = vt2.begin(); it != vt2.end(); ++it)
cout << *it << " ";
cout << endl;
}
//system("pause");
return 0;
}
2.14 重排分区算法
random_shuffle(); 随机打乱容器中数据
partition(); 分区算法,将符合谓词的元素放在前面,不符合的放在后面。但该算法不稳定,原来分区后的符合谓词的数据顺序可能和分区前的顺序不一样。
stable_partition(); 稳定分区算法,原来分区后的符合谓词的数据顺序可能和分区前的顺序不一样。
#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
using std::endl;
using std::cout;
using std::vector;
template <typename Container>
void printContainer(const Container& con, std::string str)
{
std::cout << "-----------------------------------\n" << str.c_str();
for (Container::const_iterator it = con.begin(); it != con.end(); ++it)
std::cout << *it << " ";
std::cout << "\n";
}
bool modulus3(int elem)
{
return !(elem % 3);
}
int main()
{
// ********** random_shuffle **********
vector<int> vt = {1,2,3,4,5,6,7,8,9};
printContainer(vt, "now, 容器vt中的内容为;"); // 1,2,3,4,5,6,7,8,9
random_shuffle(vt.begin(), vt.end());
printContainer(vt, "now, 容器vt中的内容为;"); // 将容器中数据随机排列
random_shuffle(vt.begin(), vt.end());
printContainer(vt, "now, 容器vt中的内容为;");
// ********** partition & stable_partition **********
//partition(vt.begin(), vt.end(), modulus3);
partition(vt.begin(), vt.end(), std::not1(std::bind2nd(std::modulus<int>(), 2))); //将偶数放在前面; 返回值为谓词逻辑的终点
printContainer(vt, "now, 容器vt中的内容为;"); // 6 4 8 2 9 5 7 1 3 // 发现偶数不是按照之前的顺序排列的
vt = { 1,2,3,4,5,6,7,8,9 };
vector<int>::iterator it = stable_partition(vt.begin(), vt.end(), std::not1(std::bind2nd(std::modulus<int>(), 2))); //将偶数放在前面
printContainer(vt, "now, 容器vt中的内容为;"); // 2 4 6 8 1 3 5 7 9 // 发现偶数不是按照之前的顺序排列的
cout << "找到的偶数为:\n";
for (vector<int>::iterator iter = vt.begin(); iter != it; ++iter)
cout << *iter << " ";
cout << endl;
//system("pause");
return 0;
}
2.15堆(heap)排序算法
将容器当做堆来处理
make_heap();
push_heap();
pop_heap();
sort_heap();
#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
using std::endl;
using std::cout;
using std::vector;
template <typename Container>
void printContainer(const Container& con, std::string str)
{
std::cout << "-----------------------------------\n" << str.c_str();
for (Container::const_iterator it = con.begin(); it != con.end(); ++it)
std::cout << *it << " ";
std::cout << "\n";
}
int main()
{
// ********** make_heap **********
vector<int> vt = {3,4,5,6,7,5,6,7,8,9,1,2,3,4}; //{1,2,3,3,4,4,5,5,6,6,7,7,8,9};
//random_shuffle(vt.begin(), vt.end());
printContainer(vt, "now, 容器vt中的内容为;"); // 3 4 5 6 7 5 6 7 8 9 1 2 3 4
make_heap(vt.begin(), vt.end());
printContainer(vt, "now, 容器vt中的内容为;"); // 9 8 6 7 7 5 5 3 6 4 1 2 3 4
pop_heap(vt.begin(), vt.end()); // 取走最大数放在末尾,剩余的数仍然是一个堆的顺序
printContainer(vt, "now, 容器vt中的内容为;"); // 8 7 6 7 4 5 5 3 6 4 1 2 3 9
vt.pop_back(); // 删除最后的9
printContainer(vt, "now, 容器vt中的内容为;"); // 8 7 6 7 4 5 5 3 6 4 1 2 3
vt.push_back(10);
printContainer(vt, "now, 容器vt中的内容为;"); // 8 7 6 7 4 5 5 3 6 4 1 2 3 10
push_heap(vt.begin(), vt.end()); // 重新生成新的堆
printContainer(vt, "now, 容器vt中的内容为;"); // 10 7 8 7 4 5 6 3 6 4 1 2 3 5
sort_heap(vt.begin(), vt.end()); // 重新将按堆的排序重新排序
printContainer(vt, "now, 容器vt中的内容为;"); // 1 2 3 3 4 4 5 5 6 6 7 7 8 10
//system("pause");
return 0;
}
2.16 排序算法
sort(b,e);
sort(b,e,op);
stable_sort(b,e);
stable_sort(b,e,op);
partial_sort(b, se, e);
partial_sort(b, se, e, op);
partial_sort_copy(sb, se, db, de);
partial_sort_copy(sb, se, db, de, op);
nth_element(b, n, e); 根据第n个元素排序
nth_element(b, n, e, op); // 与partition()类似,但partition()将满足要求的所有元素放在前面。而nth_element()只要满足要求的前n个数。
其中sort和stable_sort只能用于vevtor和deque容器,不能用于list容器(list容器有自己的内部的sort成员函数);stable_sort稳定排序。
#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
#include<iterator>
using std::endl;
using std::cout;
using std::vector;
template <typename Container>
void printContainer(const Container& con, std::string str)
{
std::cout << "-----------------------------------\n" << str.c_str();
for (Container::const_iterator it = con.begin(); it != con.end(); ++it)
std::cout << *it << " ";
std::cout << "\n";
}
int main()
{
// ********** sort & stable_sort **********
vector<int> vt = {1,3,5,7,9,8,6,4,2,9,6,3};
printContainer(vt, "now, 容器vt中的内容为;");
sort(vt.begin(), vt.end()); // stable_sort(vt.begin(), vt.end()); 默认从小到大排序,结果一样,但对于相同的元素,稳定排序保证之前相同的元素的顺序不变
printContainer(vt, "now, 容器vt中的内容为;"); // 关于稳定排序,详情请自行百度
vt = { 1,3,5,7,9,8,6,4,2,9,6,3 };
sort(vt.begin(), vt.end(), std::greater<int>()); //从大到小排序
printContainer(vt, "now, 容器vt中的内容为;"); // 9 9 8 7 6 6 5 4 3 3 2 1
// ********** partial_sort **********
vt = { 1,3,5,7,9,8,6,4,2,9,6,3 };
printContainer(vt, "now, 容器vt中的内容为;"); // 1 3 5 7 9 8 6 4 2 9 6 3
partial_sort(vt.begin(), vt.begin() + 6, vt.end()); //partial_sort(b, se, e); //相当于,找到前(se - b)个最小数
printContainer(vt, "now, 容器vt中的内容为;"); // 1 2 3 3 4 5 9 8 7 9 6 6
partial_sort(vt.begin(), vt.begin() + 6, vt.end(), std::greater<int>()); // 从大到小排序
printContainer(vt, "now, 容器vt中的内容为;"); // 9 9 8 7 6 6 1 2 3 3 4 5
// ********** partial_sort_copy **********
vector<int> vt2(4);
vt = { 1,3,5,7,9,8,6,4,2,9,6,3 };
partial_sort_copy(vt.begin(), vt.end(), vt2.begin(), vt2.end());
printContainer(vt2, "now, 容器vt2中的内容为;"); // 1 2 3 3 // 容器vt2中只有4的容量,多余的装不下
vt = { 1,3,5,7,9,8,6,4,2,9,6,3 }; // partial_sort_copy 返回值为逻辑终点
vector<int>::iterator pos = partial_sort_copy(vt2.begin(), vt2.end(), vt.begin(), vt.end()); // 将容器vt2排序的结果copy到vt中(直接覆盖前面的vt2.size()个元素,vt后面的不变)
printContainer(vt, "now, 容器vt中的内容为;"); // 1 2 3 3 9 8 6 4 2 9 6 3
cout << "复制的内容为:";
for (vector<int>::iterator iter = vt.begin(); iter != pos; ++iter)
cout << *iter << " ";
cout << endl;
// ********** nth_element ********** ???? 次方法和一般的sort有何区别???
nth_element(vt.begin(), vt.begin() + 3, vt.end(), std::greater<int>()); // 根据第n个数据排序
printContainer(vt, "now, 容器vt中的内容为;"); // 9 9 8 6 6 4 3 3 3 2 2 1
copy(vt.begin(), vt.begin() + 4, std::ostream_iterator<int>(cout, " "));
//system("pause");
return 0;
}