STL-算法
STL-算法
STL的三大组件:容器(container) 算法(algorithm) 迭代器(iterator)。
STL算法部分主要由头文件 <algorithm>,<numeric>,<functional>
组成。要使用 STL中的算法函数必须包含头文件 <algorithm>
查找统计算法
简述 | 算法名称 | 功能 |
---|---|---|
统计 | count | 返回某个元素出现的次数 |
统计 | count_if | 返回某个元素(当函数或仿函数的返回值为true)出现的次数 |
查找 | find | 根据值查找某个元素 |
查找 | find_if | 查找某个元素(当函数或仿函数的返回值为true) |
查找 | search | 查找一个序列出现的位置 |
查找 | search_n | 在范围中查找第一个连续n个元素都等价于给定值的子范围的位置 |
二分查找 | binary_search | 在有序序列中查找value,找到返回true |
统计
std::count
计算一个范围内特定元素的出现次数。
std::vector<int> my_vector = {1, 2, 3, 3, 4, 3};
int count = std::count(my_vector.begin(), my_vector.end(), 3);
std::cout << "Count of element 3: " << count << std::endl;
查找
std::find
:在一个范围内查找特定元素,返回指向该元素的迭代器。
#include <vector>
#include <algorithm>
#include <iostream>
int main()
{
std::vector<int> my_vector = {1, 2, 3, 4, 5};
auto it = std::find(my_vector.begin(), my_vector.end(), 3);
if (it != my_vector.end())
{
std::cout << "found 3 at position: " << std::distance(my_vector.begin(), it) << std::endl;
}
else
{
std::cout << "Element 3 not found" << std::endl;
}
return 0;
}
// found 3 at position: 2
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//查找内置数据类型
void test01()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
//返回一个迭代器,如果没有找到,返回end()
vector<int>::iterator it = find(v.begin(), v.end(), 5);
if (it == v.end())
cout << "没找到" << endl;
else
cout << "找到了" << *it << endl;
}
//查找自定义数据类型
class Person
{
public:
Person(string name,int age)
{
this->m_age = age;
this->m_name = name;
}
//重载==运算符,让find知道如何对比Person类型数据
bool operator==(const Person& p)
{
if (p.m_age == this->m_age && p.m_name == this->m_name)
return true;
else
return false;
}
string m_name;
int m_age;
};
void test02()
{
//准备数据
Person p1("A", 1);
Person p2("B", 2);
Person p3("C", 3);
Person p4("D", 4);
Person p5("E", 5);
//放入容器中
vector<Person>p;
p.push_back(p1);
p.push_back(p2);
p.push_back(p3);
p.push_back(p4);
p.push_back(p5);
//查找
Person p6("A", 1);
vector<Person>::iterator it = find(p.begin(), p.end(), p6);
//输出,验证结果
if (it == p.end())
cout << "没找到" << endl;
else
cout << "找到了" << it->m_name << it->m_age << endl;
}
int main()
{
test01();
test02();
return 0;
}
二分查找
std::binary_search
在一个已排序的范围内查找特定元素,如果找到则返回 true。
bool binary_search(iterator beg, iterator end, value);
查找指定的元素,查到返回true,否则返回false
注意:在无序列表中不可用,如果是无序序列,结果未知
beg //开始迭代器
end //结束迭代器
value //查找的元素
#include<iostream>
#include<vector>
#include<algorithm>
std::vector<int> my_vector = {1, 2, 3, 4, 5};
std::sort(my_vector.begin(), my_vector.end());
if (std::binary_search(my_vector.begin(), my_vector.end(), 3)) {
std::cout << "Element 3 found" << std::endl;
} else {
std::cout << "Element 3 not found" << std::endl;
}
排序和通用算法
简介 | 算法名称 | 功能 |
---|---|---|
排序 | sort | 以升序重新排列指定范围内的元素 |
排序 | stable_sort | 与sort类似,不过保留相等元素之间的顺序关系。 |
反正 | reverse | 将指定范围内元素重新反序排序。 |
随机 | random_shuffle | 对指定范围内的元素随机调整次序。 |
合并 | merge | 合并两个有序序列,存放到另一个序列 |
排序
std::sort
对一个范围内的元素进行排序。
#include<iostream>
#include<vector>
#include<algorithm>
std::vector<int> my_vector = {5, 2, 4, 1, 3};
std::sort(my_vector.begin(), my_vector.end());
for (auto x : my_vector) {
std::cout << x << " ";
}
std::cout << std::endl;
//1 2 3 4 5
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
void test01()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
//默认升序
sort(v.begin(), v.end());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " " ;
}
cout << endl;
//使用内建函数对象实现降序排列
sort(v.begin(), v.end(), greater<int>());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
}
int main()
{
test01();
return 0;
}
随机
random_shuffle(iterator beg, iterator end)
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
void test01()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
random_shuffle(v.begin(), v.end());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " " ;
}
cout << endl;
}
int main()
{
test01();
return 0;
}
合并
#include<iostream>
#include<vector>
#include<algorithm>
int main() {
std::vector<int> v1 = {5, 2, 4, 1, 3};
std::vector<int> v2 = {5, 2, 4, 1, 3};
std::vector<int> v3;
v3.resize(v1.size() + v2.size());
std::sort(v1.begin(), v1.end());
for (auto x : v1) {
std::cout << x << " ";
}
std::cout << std::endl;
//1 2 3 4 5
std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
for (auto x : v3) {
std::cout << x << " ";
}
std::cout << std::endl;
//1 2 3 4 5 5 2 4 1 3
return 0;
}
反转
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
void Print(int val)
{
cout << val << " ";
}
void test01()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
for_each(v1.begin(), v1.end(), Print);
cout << endl;
//反转
reverse(v1.begin(), v1.end());
for_each(v1.begin(), v1.end(), Print);
}
int main()
{
test01();
return 0;
}
复制替换删除算法
序号 | 算法名称 | 功能 |
---|---|---|
拷贝 | copy | 将容器内指定范围内的元素拷贝到目标容器。 |
替换 | replace | 将容器指定范围的旧元素替换为新元素 |
替换 | replace_if | 将容器区间内满足条件的元素,替换成新元素 |
唯一 | unique | 清除序列中相邻的重复元素 |
互换 | swap | 互换两个容器的元素 |
删除 | remove | 删除指定范围内所有等于指定元素的元素 |
复制替换
#include<iostream>
#include<vector>
#include<algorithm> //算法头文件
using namespace std;
struct Judge_Elem
{
bool operator()(int x) // 判断这个值是否为3
{
return x == 6 | x== 9;
}
};
void Print(int x)
{
cout << x << " "; // 打印元素
}
int main()
{
//数据都在容器中
vector<int> v = { 1,2,3,4,5,6 };
vector<int> v_copy(v.size());
copy(v.begin(), v.end(), v_copy.begin());
// 替换元素
replace(v.begin(), v.end(),3,9);
for_each(v.begin(), v.end(), Print);
cout << endl;
// 条件替换元素
replace_if(v.begin(), v.end(), Judge_Elem(), 0);
for_each(v.begin(), v.end(), Print);
cout << endl;
cout << "----------------------------------------" << endl;
}
删除唯一
#include<iostream>
#include<vector>
#include<algorithm> //算法头文件
using namespace std;
void Print(int x)
{
cout << x << " "; // 打印元素
}
int main()
{
//数据都在容器中
vector<int> v1 = { 1,3,2,3,4,5,6};
//删除所有的特定元素,但是不会改变容器的大小,只会将后面的元素往前移动,
//并返回删除后最后一个元素的结束位置
vector<int>::iterator itNewEnd=remove(v1.begin(), v1.end(), 3);
//打印
for_each(v1.begin(), itNewEnd, Print);
cout << endl;
//数据都在容器中
vector<int> v2 = { 1,2,3,3,3,4,5,6 };
//删除【连续相同元素】,只保留一个,但是不会改变容器的大小,只会将后面的元素往前移动,
//并返回删除后最后一个元素的结束位置,类似remove
vector<int>::iterator itNewEnd = unique(v2.begin(), v2.end());
//打印
for_each(v2.begin(), itNewEnd, Print);
cout << endl;
}
// 1 2 4 5 6
// 1 2 3 4 5 6
互换
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Print
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
class GreaterFive
{
public:
bool operator()(const int& val)
{
return val > 5;
}
};
void test01()
{
vector<int>v1;
vector<int>v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i + 2);
}
//交换前
for_each(v1.begin(), v1.end(), Print());
for_each(v2.begin(), v2.end(), Print());
cout << endl;
//交换后
swap(v1, v2);
for_each(v1.begin(), v1.end(), Print());
for_each(v2.begin(), v2.end(), Print());
}
int main()
{
test01();
return 0;
}
生成和异变算法
简述 | 算法名称 | 功能 |
---|---|---|
填充 | fill | 将输入值赋给标志范围内的所有元素 |
转换 | transform | 将输入的操作作用与指定范围内的每个元素,并产生一个新的序列 |
生成 | generate | 连续调用输入的函数来填充指定的范围 |
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
void Print(int x)
{
cout << x << " "; // 打印元素
}
class even_by_two
{
private:
static int _x; // 注意静态变量
public:
int operator()()const
{
return _x += 2;
}
};
int even_by_two::_x = 0; // 初始化静态变量
void test01()
{
vector<int> v1={1,2,3,4,5,6,7,8,9};
vector<int> iv(10);
for_each(v1.begin(), v1.end(), Print);
cout << endl;
fill(v1.begin(), v1.end(), 9);
for_each(v1.begin(), v1.end(), Print);
cout << endl;
generate(iv.begin(), iv.end(), even_by_two());
for_each(iv.begin(), iv.end(), Print);
cout << endl;
}
int main()
{
test01();
return 0;
}
数值算法
简述 | 算法名称 | 功能 |
---|---|---|
累加 | accumulate | 计算容器元素累计总和 |
partial_sum | 每个元素值代表指定范围内该位置前所有元素之和 | |
内积 | inner_product | 内积,对应元素相乘,再求和 |
adjacent_difference | 计算相邻元素的差 |
#include <iostream>
#include <vector>
#include <numeric> // 数值算法
#include <iterator> // 定义了ostream_iterator
#include<algorithm>
using namespace std;
void Print(int x){
cout << x << " ";
};
int main(int argc, char* argv[])
{
int arr[] = { 1, 2, 3, 4, 5 };
vector<int> vec(arr, arr + 5);
vector<int> vec2(arr, arr + 5);
for_each(vec.begin(), vec.end(), Print);
cout << endl;
// accumulate: iterator对标识的序列段元素之和,加到一个由val指定的初始值上。
int temp;
int val = 0;
temp = accumulate(vec.begin(), vec.end(), val);
cout << "accumulate(val = 0): " << temp << endl;
val = 1;
temp = accumulate(vec.begin(), vec.end(), val);
cout << "accumulate(val = 1): " << temp << endl;
// inner_product: 对两个序列做内积(对应元素相乘,再求和)并将内积加到一个输入的初始值上。
// 这里是:1*1 + 2*2 + 3*3 + 4*4 + 5*5
val = 0;
temp = inner_product(vec.begin(), vec.end(), vec2.begin(), val);
cout << "inner_product(val = 0): " << temp << endl;
// partial_sum: 创建一个新序列,其中每个元素值代表指定范围内该位置前所有元素之和。
// 第一次,1 第二次,1+2 第三次,1+2+3 第四次,1+2+3+4
ostream_iterator<int> oit(cout, " "); // 迭代器绑定到cout上作为输出使用
cout << "ostream_iterator: ";
partial_sum(vec.begin(), vec.end(), oit);// 依次输出前n个数的和
cout << endl;
// 第一次,1 第二次,1-2 第三次,1-2-3 第四次,1-2-3-4
cout << "ostream_iterator(minus): ";
partial_sum(vec.begin(), vec.end(), oit, minus<int>());// 依次输出第一个数减去(除第一个数外到当前数的和)
cout << endl;
// adjacent_difference: 创建一个新序列,新序列中每个新值代表当前元素与上一个元素的差。
// 第一次,1-0 第二次,2-1 第三次,3-2 第四次,4-3
cout << "adjacent_difference: ";
adjacent_difference(vec.begin(), vec.end(), oit); // 输出相邻元素差值 后面-前面
cout << endl;
// 第一次,1+0 第二次,2+1 第三次,3+2 第四次,4+3
cout << "adjacent_difference(plus): ";
adjacent_difference(vec.begin(), vec.end(), oit, plus<int>()); // 输出相邻元素差值 后面-前面
cout << endl;
return 0;
}
/*
accumulate(val = 0): 15
accumulate(val = 1): 16
inner_product(val = 0): 55
ostream_iterator: 1 3 6 10 15
ostream_iterator(minus): 1 -1 -4 -8 -13
adjacent_difference: 1 1 1 1 1
adjacent_difference(plus): 1 3 5 7 9
*/
关系集合算法
简述 | 算法名称 | 功能 |
---|---|---|
交集 | set_intersection | 求两个容器的交集 |
并集 | set_union | 求两个容器的并集 |
差集 | set_difference | 求两个容器的差集 |
交并集
set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
//求两个容器的交集
beg1 //容器1开始迭代器
end1 //容器1结束迭代器
beg2 //容器2开始迭代器
end2 //容器2结束迭代器
dest //目标容器开始迭代器
# 返回值为迭代器,指向交集最后一个元素的下一个位置
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
void myPrint(int val)
{
cout << val << " ";
}
void test01()
{
vector<int>v1={1,2,3,4,5,6,7,8,9};
vector<int>v2={5,6,7,8,9,10,11,12,13,14};
for_each(v1.begin(), v1.end(), myPrint);
cout << endl;
for_each(v2.begin(), v2.end(), myPrint);
cout << endl;
//目标容器需要提前开辟空间,最特殊的情况,大容器包含小容器
vector<int>v3;
v3.resize(min(v1.size(), v2.size()));
//取交集
vector<int>::iterator itEnd = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
for_each(v3.begin(), itEnd, myPrint);
cout << endl;
//如果不用返回的itEnd,会把0也给打印出来
for_each(v3.begin(), v3.end(), myPrint);
}
int main()
{
test01();
return 0;
}
set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
//求两个容器的并集
beg1 //容器1开始迭代器
end1 //容器1结束迭代器
beg2 //容器2开始迭代器
end2 //容器2结束迭代器
dest //目标容器开始迭代器
# 返回值为迭代器,指向并集最后一个元素的下一个位置
vector<int>v4;
v4.resize(v1.size() + v2.size());
vector<int>::iterator ituEnd = set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), v4.begin());
for_each(v4.begin(), ituEnd, myPrint);
实践操作
Vector中去重
对于STL去重,可以使用
unique()函数用于去除相邻元素中的重复元素(所以去重前需要对vector进行排序),只留下一个。返回去重后的尾地址。
unique()并不会删除vector中的元素,只是将重复元素替换为之后的元素,vector的大小并不会改变。
所以之后还需要调用erase()函数,删除之后的元素。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(int argc, char *argv[])
{
vector<int> nums;
for (int i = 0; i < 10; i++)
nums.push_back(i % 8);
cout << "before sort..." << endl;
for (size_t i = 0; i < nums.size(); i++)
cout << nums[i] << " ";
cout << endl;
cout << "after sort..." << endl;
sort(nums.begin(), nums.end());
for (size_t i = 0; i < nums.size(); i++)
cout << nums[i] << " ";
cout << endl;
auto iter = unique(nums.begin(), nums.end());
cout << "before unique() size:" << nums.size() << "\nafter unique() size:" << nums.size() << endl;
nums.erase(iter, nums.end());
for (size_t i = 0; i < nums.size(); i++)
cout << nums[i] << " ";
cout << endl;
getchar();
return 0;
}
参考资料
https://juejin.cn/post/7301496834232614951?from=search-suggest#heading-24
https://blog.csdn.net/u014779536/article/details/116380670 详细
https://www.cnblogs.com/linuxAndMcu/p/10264339.html
https://www.cnblogs.com/BeyondAnyTime/archive/2012/05/27/2520532.html