【C++提高】算法

news/2024/9/25 10:25:45/

算法

  • 一、遍历算法
    • 1. for_each
    • 2. transform
  • 二、查找算法
    • 1. find
    • 2. find_if
    • 3. adjacent_find
    • 4. binary_search
    • 5. count
    • 6. count_if
  • 三、排序算法
    • 1. sort
    • 2. random_shuffle
    • 3. merge
    • 4. reverse
  • 四、拷贝和替换算法
    • 1. copy
    • 2. replace
    • 3. replace_if
    • 4. swap
  • 五、算术生成算法
    • 1. accumulate
    • 2. fill
  • 六、集合算法
    • 1. set_intersection
    • 2. set_union
    • 3. set_difference
  • 七、用法对比

算法主要是由头文件 <algorithm><functional><numeric>组成。 <algorithm>是所有STL头文件中最大的一个,范围涉及到比较、 交换、查找、遍历操作、复制、修改等等; <numeric>体积很小,只包括几个在序列上面进行简单数学运算的模板函数; <functional>定义了一些模板类,用以声明函数对象。

一、遍历算法

1. for_each

实现遍历容器,函数原型为for_each(iterator beg, iterator end, _func); 。其中,beg为开始迭代器,end为结束迭代器,_func为函数或者函数对象。

#include <algorithm>
#include <vector>//普通函数
void print01(int val) 
{cout << val << " ";
}
//函数对象
class print02 
{public:void operator()(int val) {cout << val << " ";}
};//for_each算法基本用法
void test01() {vector<int> v;for (int i = 0; i < 10; i++) {v.push_back(i);}//遍历算法for_each(v.begin(), v.end(), print01);cout << endl;for_each(v.begin(), v.end(), print02());cout << endl;
}int main() {test01();system("pause");return 0;
}

2. transform

搬运容器到另一个容器中,函数原型为transform(iterator beg1, iterator end1, iterator beg2, _func);。其中,beg1为源容器开始迭代器,end1为源容器结束迭代器,beg2为目标容器开始迭代器,_func为函数或者函数对象。注意,目标容器需要提前开辟空间。

#include<vector>
#include<algorithm>//常用遍历算法  搬运 transformclass TransForm
{
public:int operator()(int val){return val;}};class MyPrint
{
public:void operator()(int val){cout << val << " ";}
};void test01()
{vector<int>v;for (int i = 0; i < 10; i++){v.push_back(i);}vector<int>vTarget; //目标容器vTarget.resize(v.size()); // 目标容器需要提前开辟空间transform(v.begin(), v.end(), vTarget.begin(), TransForm());for_each(vTarget.begin(), vTarget.end(), MyPrint());
}int main() {test01();system("pause");return 0;
}

二、查找算法

1. find

查找指定元素,找到返回指定元素的迭代器,找不到返回结束迭代器end()。函数原型为find(iterator beg, iterator end, value); 。其中,beg为开始迭代器,end为结束迭代器,value为查找的元素。

#include <algorithm>
#include <vector>
#include <string>
void test01() {vector<int> v;for (int i = 0; i < 10; i++) {v.push_back(i + 1);}//查找容器中是否有 5 这个元素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_Name = name;this->m_Age = age;}//重载==bool operator==(const Person& p) {if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) {return true;}return false;}public:string m_Name;int m_Age;
};void test02() {vector<Person> v;//创建数据Person p1("aaa", 10);Person p2("bbb", 20);Person p3("ccc", 30);Person p4("ddd", 40);v.push_back(p1);v.push_back(p2);v.push_back(p3);v.push_back(p4);vector<Person>::iterator it = find(v.begin(), v.end(), p2);if (it == v.end()) {cout << "没有找到!" << endl;}else {cout << "找到姓名:" << it->m_Name << " 年龄: " << it->m_Age << endl;}
}

2. find_if

按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置。函数原型为find_if(iterator beg, iterator end, _Pred); 。其中,beg为开始迭代器,end为结束迭代器,_Pred为函数或者谓词(返回bool类型的仿函数)。

#include <algorithm>
#include <vector>
#include <string>//内置数据类型
class GreaterFive
{
public:bool operator()(int val){return val > 5;}
};void test01() {vector<int> v;for (int i = 0; i < 10; i++) {v.push_back(i + 1);}vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());if (it == v.end()) {cout << "没有找到!" << endl;}else {cout << "找到大于5的数字:" << *it << endl;}
}//自定义数据类型
class Person {
public:Person(string name, int age){this->m_Name = name;this->m_Age = age;}
public:string m_Name;int m_Age;
};class Greater20
{
public:bool operator()(Person &p){return p.m_Age > 20;}};void test02() {vector<Person> v;//创建数据Person p1("aaa", 10);Person p2("bbb", 20);Person p3("ccc", 30);Person p4("ddd", 40);v.push_back(p1);v.push_back(p2);v.push_back(p3);v.push_back(p4);vector<Person>::iterator it = find_if(v.begin(), v.end(), Greater20());if (it == v.end()){cout << "没有找到!" << endl;}else{cout << "找到姓名:" << it->m_Name << " 年龄: " << it->m_Age << endl;}
}int main() {//test01();test02();system("pause");return 0;
}

3. adjacent_find

查找相邻重复元素,返回相邻元素的第一个位置的迭代器。函数原型为adjacent_find(iterator beg, iterator end); 。其中,beg为开始迭代器,end为结束迭代器。

#include <algorithm>
#include <vector>void test01()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(5);v.push_back(2);v.push_back(4);v.push_back(4);v.push_back(3);//查找相邻重复元素vector<int>::iterator it = adjacent_find(v.begin(), v.end());if (it == v.end()) {cout << "找不到!" << endl;}else {cout << "找到相邻重复元素为:" << *it << endl;}
}

4. binary_search

查找指定的元素,查到返回true,否则返回false。该算法在无序序列中不可用。函数原型
bool binary_search(iterator beg, iterator end, value); 。其中,beg为开始迭代器,end为结束迭代器,value为查找的元素。

#include <algorithm>
#include <vector>void test01()
{vector<int>v;for (int i = 0; i < 10; i++){v.push_back(i);}//二分查找bool ret = binary_search(v.begin(), v.end(),2);if (ret){cout << "找到了" << endl;}else{cout << "未找到" << endl;}
}int main() {test01();system("pause");return 0;
}

5. count

统计元素出现次数。函数原型为count(iterator beg, iterator end, value);。其中,beg为开始迭代器,end为结束迭代器,value为统计的元素。

#include <algorithm>
#include <vector>//内置数据类型
void test01()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(4);v.push_back(5);v.push_back(3);v.push_back(4);v.push_back(4);int num = count(v.begin(), v.end(), 4);cout << "4的个数为: " << num << endl;
}//自定义数据类型
class Person
{
public:Person(string name, int age){this->m_Name = name;this->m_Age = age;}bool operator==(const Person & p){if (this->m_Age == p.m_Age){return true;}else{return false;}}string m_Name;int m_Age;
};void test02()
{vector<Person> v;Person p1("刘备", 35);Person p2("关羽", 35);Person p3("张飞", 35);Person p4("赵云", 30);Person p5("曹操", 25);v.push_back(p1);v.push_back(p2);v.push_back(p3);v.push_back(p4);v.push_back(p5);Person p("诸葛亮",35);int num = count(v.begin(), v.end(), p);cout << "num = " << num << endl;
}
int main() {//test01();test02();system("pause");return 0;
}

6. count_if

按条件统计元素出现次数。函数原型为count_if(iterator beg, iterator end, _Pred);。其中,beg为开始迭代器,end为结束迭代器,_Pred为函数或者谓词(返回bool类型的仿函数)。

#include <algorithm>
#include <vector>class Greater4
{
public:bool operator()(int val){return val >= 4;}
};//内置数据类型
void test01()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(4);v.push_back(5);v.push_back(3);v.push_back(4);v.push_back(4);int num = count_if(v.begin(), v.end(), Greater4());cout << "大于4的个数为: " << num << endl;
}//自定义数据类型
class Person
{
public:Person(string name, int age){this->m_Name = name;this->m_Age = age;}string m_Name;int m_Age;
};class AgeLess35
{
public:bool operator()(const Person &p){return p.m_Age < 35;}
};
void test02()
{vector<Person> v;Person p1("刘备", 35);Person p2("关羽", 35);Person p3("张飞", 35);Person p4("赵云", 30);Person p5("曹操", 25);v.push_back(p1);v.push_back(p2);v.push_back(p3);v.push_back(p4);v.push_back(p5);int num = count_if(v.begin(), v.end(), AgeLess35());cout << "小于35岁的个数:" << num << endl;
}int main() {//test01();test02();system("pause");return 0;
}

三、排序算法

1. sort

对容器内元素进行排序。函数原型为sort(iterator beg, iterator end, _Pred);。其中,beg为开始迭代器,end为结束迭代器,_Pred为函数或者谓词(返回bool类型的仿函数)。

#include <algorithm>
#include <vector>void myPrint(int val)
{cout << val << " ";
}void test01() {vector<int> v;v.push_back(10);v.push_back(30);v.push_back(50);v.push_back(20);v.push_back(40);//sort默认从小到大排序sort(v.begin(), v.end());for_each(v.begin(), v.end(), myPrint);cout << endl;//从大到小排序sort(v.begin(), v.end(), greater<int>());for_each(v.begin(), v.end(), myPrint);cout << endl;
}int main() {test01();system("pause");return 0;
}

2. random_shuffle

指定范围内的元素随机调整次序。函数原型为random_shuffle(iterator beg, iterator end);。其中,beg为开始迭代器,end为结束迭代器。使用时记得加随机数种子srand((unsigned int)time(NULL));

#include <algorithm>
#include <vector>
#include <ctime>class myPrint
{
public:void operator()(int val){cout << val << " ";}
};void test01()
{srand((unsigned int)time(NULL));vector<int> v;for(int i = 0 ; i < 10;i++){v.push_back(i);}for_each(v.begin(), v.end(), myPrint());cout << endl;//打乱顺序random_shuffle(v.begin(), v.end());for_each(v.begin(), v.end(), myPrint());cout << endl;
}int main() {test01();system("pause");return 0;
}

3. merge

两个容器元素合并,并存储到另一容器中。函数原型为merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);。两个容器必须是有序的。其中,beg1是容器1开始迭代器,end1是容器1结束迭代器,beg2是容器2开始迭代器,end2是容器2结束迭代器,dest是目标容器开始迭代器。注意,目标容器需要提前开辟空间。

#include <algorithm>
#include <vector>class myPrint
{
public:void operator()(int val){cout << val << " ";}
};void test01()
{vector<int> v1;vector<int> v2;for (int i = 0; i < 10 ; i++) {v1.push_back(i);v2.push_back(i + 1);}vector<int> vtarget;//目标容器需要提前开辟空间vtarget.resize(v1.size() + v2.size());//合并  需要两个有序序列merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vtarget.begin());for_each(vtarget.begin(), vtarget.end(), myPrint());cout << endl;
}int main() {test01();system("pause");return 0;
}

4. reverse

将容器内元素进行反转。函数原型为reverse(iterator beg, iterator end);。其中,beg为开始迭代器,end为结束迭代器。

#include <algorithm>
#include <vector>class myPrint
{
public:void operator()(int val){cout << val << " ";}
};void test01()
{vector<int> v;v.push_back(10);v.push_back(30);v.push_back(50);v.push_back(20);v.push_back(40);cout << "反转前: " << endl;for_each(v.begin(), v.end(), myPrint());cout << endl;cout << "反转后: " << endl;reverse(v.begin(), v.end());for_each(v.begin(), v.end(), myPrint());cout << endl;
}int main() {test01();system("pause");return 0;
}

四、拷贝和替换算法

1. copy

容器内指定范围的元素拷贝到另一容器中。函数原型为copy(iterator beg, iterator end, iterator dest);。其中,beg为开始迭代器,end为结束迭代器,dest为目标开始迭代器。注意,需要提前为目标容器开辟空间。

#include <algorithm>
#include <vector>class myPrint
{
public:void operator()(int val){cout << val << " ";}
};void test01()
{vector<int> v1;for (int i = 0; i < 10; i++) {v1.push_back(i + 1);}vector<int> v2;v2.resize(v1.size());copy(v1.begin(), v1.end(), v2.begin());for_each(v2.begin(), v2.end(), myPrint());cout << endl;
}int main() {test01();system("pause");return 0;
}

2. replace

将容器内指定范围的旧元素修改为新元素。函数原型为replace(iterator beg, iterator end, oldvalue, newvalue);。其中,beg为开始迭代器,end为结束迭代器,oldvalue为旧元素,newvalue为新元素。

#include <algorithm>
#include <vector>class myPrint
{
public:void operator()(int val){cout << val << " ";}
};void test01()
{vector<int> v;v.push_back(20);v.push_back(30);v.push_back(20);v.push_back(40);v.push_back(50);v.push_back(10);v.push_back(20);cout << "替换前:" << endl;for_each(v.begin(), v.end(), myPrint());cout << endl;//将容器中的20 替换成 2000cout << "替换后:" << endl;replace(v.begin(), v.end(), 20,2000);for_each(v.begin(), v.end(), myPrint());cout << endl;
}int main() {test01();system("pause");return 0;
}

3. replace_if

将区间内满足条件的元素,替换成指定元素。函数原型为replace_if(iterator beg, iterator end, _pred, newvalue);。其中,beg为开始迭代器,end为结束迭代器,_Pred为函数或者谓词(返回bool类型的仿函数),newvalue为新元素。

#include <algorithm>
#include <vector>class myPrint
{
public:void operator()(int val){cout << val << " ";}
};class ReplaceGreater30
{
public:bool operator()(int val){return val >= 30;}};void test01()
{vector<int> v;v.push_back(20);v.push_back(30);v.push_back(20);v.push_back(40);v.push_back(50);v.push_back(10);v.push_back(20);cout << "替换前:" << endl;for_each(v.begin(), v.end(), myPrint());cout << endl;//将容器中大于等于的30 替换成 3000cout << "替换后:" << endl;replace_if(v.begin(), v.end(), ReplaceGreater30(), 3000);for_each(v.begin(), v.end(), myPrint());cout << endl;
}int main() {test01();system("pause");return 0;
}

4. swap

互换两个容器的元素。函数原型为swap(container c1, container c2);。其中,c1和c2为两个需要互换的容器。注意,互换的容器需要同种类型。

#include <algorithm>
#include <vector>class myPrint
{
public:void operator()(int val){cout << val << " ";}
};void test01()
{vector<int> v1;vector<int> v2;for (int i = 0; i < 10; i++) {v1.push_back(i);v2.push_back(i+100);}cout << "交换前: " << endl;for_each(v1.begin(), v1.end(), myPrint());cout << endl;for_each(v2.begin(), v2.end(), myPrint());cout << endl;cout << "交换后: " << endl;swap(v1, v2);for_each(v1.begin(), v1.end(), myPrint());cout << endl;for_each(v2.begin(), v2.end(), myPrint());cout << endl;
}int main() {test01();system("pause");return 0;
}

五、算术生成算法

算术生成算法属于小型算法,使用时包含的头文件为 #include <numeric>

1. accumulate

计算区间内容器元素累计总和。函数原型为accumulate(iterator beg, iterator end, value);。其中,beg为开始迭代器,end为结束迭代器,value为叠加起始值。

#include <numeric>
#include <vector>
void test01()
{vector<int> v;for (int i = 0; i <= 100; i++) {v.push_back(i);}int total = accumulate(v.begin(), v.end(), 0);cout << "total = " << total << endl;
}int main() {test01();system("pause");return 0;
}

2. fill

向容器中填充指定的元素。函数原型为fill(iterator beg, iterator end, value);。其中,beg为开始迭代器,end为结束迭代器,value为填充的值。

#include <numeric>
#include <vector>
#include <algorithm>class myPrint
{
public:void operator()(int val){cout << val << " ";}
};void test01()
{vector<int> v;v.resize(10);//填充fill(v.begin(), v.end(), 100);for_each(v.begin(), v.end(), myPrint());cout << endl;
}int main() {test01();system("pause");return 0;
}

六、集合算法

1. set_intersection

求两个容器的交集。函数原型为set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);。其中,beg1为容器1开始迭代器,end1为容器1结束迭代器,beg2为容器2开始迭代器,end2为容器2结束迭代器,dest为目标容器开始迭代器,返回值为填充后的迭代器。注意,两个集合必须是有序序列,且目标容器需要提前开辟空间,目标容器开辟空间需要从两个容器中取小值。

#include <vector>
#include <algorithm>class myPrint
{
public:void operator()(int val){cout << val << " ";}
};void test01()
{vector<int> v1;vector<int> v2;for (int i = 0; i < 10; i++){v1.push_back(i);v2.push_back(i+5);}vector<int> vTarget;//取两个里面较小的值给目标容器开辟空间vTarget.resize(min(v1.size(), v2.size()));//返回目标容器的最后一个元素的迭代器地址vector<int>::iterator itEnd = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());for_each(vTarget.begin(), itEnd, myPrint());cout << endl;
}int main() {test01();system("pause");return 0;
}

2. set_union

求两个集合的并集。函数原型为set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);。其中,beg1为容器1开始迭代器,end1为容器1结束迭代器,beg2为容器2开始迭代器,end2为容器2结束迭代器,dest为目标容器开始迭代器,返回值为填充后的迭代器。注意,两个集合必须是有序序列,且目标容器需要提前开辟空间,目标容器开辟空间需要两个容器相加。

#include <vector>
#include <algorithm>class myPrint
{
public:void operator()(int val){cout << val << " ";}
};void test01()
{vector<int> v1;vector<int> v2;for (int i = 0; i < 10; i++) {v1.push_back(i);v2.push_back(i+5);}vector<int> vTarget;//取两个容器的和给目标容器开辟空间vTarget.resize(v1.size() + v2.size());//返回目标容器的最后一个元素的迭代器地址vector<int>::iterator itEnd = set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());for_each(vTarget.begin(), itEnd, myPrint());cout << endl;
}int main() {test01();system("pause");return 0;
}

3. set_difference

求两个集合的差集。函数原型为set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);。其中,beg1为容器1开始迭代器,end1为容器1结束迭代器,beg2为容器2开始迭代器,end2为容器2结束迭代器,dest为目标容器开始迭代器,返回值为填充后的迭代器。注意,两个集合必须是有序序列,且目标容器需要提前开辟空间,目标容器开辟空间需要两个容器取较大值。

#include <vector>
#include <algorithm>class myPrint
{
public:void operator()(int val){cout << val << " ";}
};void test01()
{vector<int> v1;vector<int> v2;for (int i = 0; i < 10; i++) {v1.push_back(i);v2.push_back(i+5);}vector<int> vTarget;//取两个里面较大的值给目标容器开辟空间vTarget.resize( max(v1.size() , v2.size()));//返回目标容器的最后一个元素的迭代器地址cout << "v1与v2的差集为: " << endl;vector<int>::iterator itEnd = set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());for_each(vTarget.begin(), itEnd, myPrint());cout << endl;cout << "v2与v1的差集为: " << endl;itEnd = set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), vTarget.begin());for_each(vTarget.begin(), itEnd, myPrint());cout << endl;
}int main() {test01();system("pause");return 0;
}

七、用法对比

算法是否支持操作set和map是否对内部数据顺序有要求是否支持内部数据为自定义类型
for_each支持无要求支持
transform支持无要求支持
find支持无要求支持但自定义类需要重载运算符==
find_if支持无要求支持但需要加入谓词做参数
adjacent_find不支持无要求支持但需要加入谓词做参数
swap支持无要求支持
binary_search支持必须升序不支持
count支持无要求支持但自定义类需要重载运算符==
count_if支持无要求支持但需要加入谓词做参数
sort不支持无要求支持但需要加入谓词做参数
random_shuffle不支持无要求支持
merge不支持必须升序不支持
reverse不支持无要求支持
copy不支持无要求支持
replace不支持无要求支持但自定义类需要重载运算符==
replace_if不支持无要求支持但需要加入谓词做参数
swap支持无要求支持
accumulate支持无要求支持
fill不支持无要求支持
set_intersection不支持必须升序不支持
set_union不支持必须升序不支持
set_difference不支持必须升序不支持

http://www.ppmy.cn/news/1430776.html

相关文章

国产人工智能语言大模型相关网站

以下给大家分享了一些国产人工智能语言大模型相关网站&#xff0c;仅供参考。&#xff08;大语言模型仅仅是作为辅助工具&#xff0c;实际应用中还是要多思考和学习&#xff09; 1.字节豆包&#xff1a;豆包 2.文心一言&#xff1a;文心一言 3.讯飞星火&#xff1a;讯飞星火…

PLSQL中文乱码问题 + EZDML导入数据库模型乱码

PLSQL中文乱码问题 EZDML导入数据库模型乱码 查询数据库字符集 select userenv(language) from dual;查询本地字符集编码 select * from V$NLS_PARAMETERS;理论上 数据库字符集 跟 本地字符集编码 是一致的 本地字符集编码需要拼接字段值 NLS_LANGUAGE NLS_TERRITORY NLS…

试用花生壳软件,实现外网访问内网web服务器

试用花生壳软件&#xff0c;实现外网访问内网web服务器。今天查看了一下家用的WiFi路由器和光猫。在wifi路由器里看到了DDNS&#xff0c;看到了花生壳。这时想到了花生壳软件能实现外网访问内网web服务器的功能。于是试用了一下。 先游览了贝锐花生壳公司网站&#xff0c;了解…

EelasticSearch的介绍和基于docker安装

1.概述 Elasticsearch 是一个基于 Apache Lucene 构建的开源分布式搜索引擎和分析引擎。它专为云计算环境设计&#xff0c;提供了一个分布式的、高可用的实时分析和搜索平台。Elasticsearch 可以处理大量数据&#xff0c;并且具备横向扩展能力&#xff0c;能够通过增加更多的硬…

Storm详细配置

要详细配置 Apache Storm&#xff0c;你需要关注以下几个方面&#xff1a; Topology配置&#xff1a; ● 定义你的拓扑结构&#xff0c;包括哪些Spout和Bolt将被使用&#xff0c;它们之间的连接关系&#xff0c;以及拓扑如何处理数据流。 ● 设置每个组件的并行度&#xff0c…

如何从零开发一个脚手架

1 创建工程 1.1 创建文件并安装依赖 创建一个my-cli文件夹执行npm init初始化工程安装依赖创建入口文件, index.js 依赖名称依赖版本依赖作用chalk4.1.2log美化工具cli-table0.3.11控制台table美化工具commander11.1.0命令行工具download-git-repo3.0.2拉取远程模板ejs3.1.1…

高可用集群——keepalived

目录 1 高可用的概念 2 心跳监测与漂移 IP 地址 3 Keepalived服务介绍 4 Keepalived故障切换转移原理介绍 5 Keepalived 实现 Nginx 的高可用集群 5.1 项目背景 5.2 项目环境 5.3 项目部署 5.3.1 web01\web02配置&#xff1a; 5.3.2nginx负载均衡配置 5.3.3 主调度服…

ABC350A-F题解

ABC350 A-E题解 A题目AC Code&#xff08;CPP&#xff09;&#xff1a;AC Code&#xff08;Python&#xff09;: B题目AC Code&#xff08;CPP&#xff09;&#xff1a;AC Code&#xff08;Python&#xff09;&#xff1a; C题目AC Code&#xff08;CPP&#xff09;&#xff1a…