STL 算法小结
https://blog.csdn.net/codedz/article/details/110493577 仅供学习 部分内容有改动
1.sort()快排
函数原型:sort(起始地址, 末尾地址, cmp)
,其中cmp
是可以自己定义的函数名.
- 数组排序示例
#include<bits/stdc++.h>
using namespace std;
int main(){
int a[5] = {5,2,3,9,1};
sort(a, a + 5);
for(int i = 0; i < 5; i++) cout << a[i] << ' ';
cout << endl;
return 0;
}
输出为:1 2 3 5 9
- vector排序示例
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<int> vec = {5,2,3,9,1};
sort(vec.begin(), vec.end());
for(int v : vec) cout << v << ' ';
cout << endl;
return 0;
}
- 自定义
cmp
示例(也可对结构体排序使用)仿函数也可以使用
#include<bits/stdc++.h>
using namespace std;
bool cmp(int &a, int &b){ // 使用简单的比较函数
return a > b;
}
int main(){
vector<int> vec = {5,2,3,9,1};
sort(vec.begin(), vec.end(), cmp);
sort(vec.begin(), vec.end(), greater<int>()); // 使用仿函数
sort(vec.begin(), vec.end(), greater<>()); // 使用仿函数
for(int v : vec) cout << v << ' ';
cout << endl;
return 0;
}
2.reverse()逆置
函数原型:reverse(起始地址, 末尾地址);
vector示例(数组同上):
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<int> vec = {5,2,3,9,1};
reverse(vec.begin(), vec.end());
for(int v : vec) cout << v << ' ';
cout << endl;
return 0;
}
输出为:1 9 3 2 5
3.unique()去重
函数原型:unique(起始地址, 末尾地址, fun);
其中fun为自定义的函数名。
如果想很好地使用unique(), 首先要对原数组进行排序
注意:unique函数去重并不是真正的去重,它是不断的将后面不重复的元素覆盖前面重复的元素,最后返回最后一个不重复的元素的地址。下面来看看示例:
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<int> vec = {1,1,2,3,3,4,4,5};
auto pos = unique(vec.begin(), vec.end()) - vec.begin();
//打印输出使用了unique函数后的vec
for(int i : vec) cout << i << ' ';
cout << endl << "最后一个不重复的元素是:" << pos << endl;
return 0;
}
输出为:
1 2 3 4 5 4 4 5
最后一个不重复的元素是:5
可以看出用了unique()
函数并不能真正将vec
去重,那么要如何做才能真正去重呢?
答案是用erase()
方法,请看示例:
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<int> vec = {1,1,2,3,3,4,4,5};
auto pos = unique(vec.begin(), vec.end());
vec.erase(pos, vec.end());
for(int v : vec) cout << v << ' ';
cout << endl;
return 0;
}
4.查找函数
二分查找函数
lower_bound(起始地址, 末尾地址, target):查找第一个大于等于target目标值的位置
upper_bound(起始地址, 末尾地址, target):查找第一个大于target目标值的位置
binary_search(起始地址, 末尾地址, target):查找target是否存在于数组或vector中,找到返回true,否则返回false
这三种方法都是采用的二分查找实现的函数,用于有序数组或vector等,查找效率较高,实际写题时,直接用能较少很多代码量。下面来看看示例吧:
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<int> vec = {1,1,2,3,3,4,4,5};
auto pos1 = lower_bound(vec.begin(), vec.end(), 2) - vec.begin();
auto pos2 = upper_bound(vec.begin(), vec.end(), 2) - vec.begin();
auto flag = binary_search(vec.begin(), vec.end(), 2);
cout << "第一个大于等于2的位置是" << pos1 << endl;
cout << "第一个大于2的位置是" << pos2 << endl;
cout << "查找2返回的结果:" << flag << endl;
return 0;
}
输出如下:
第一个大于等于2的位置是2
第一个大于2的位置是3
查找2返回的结果:1
- 字符串查找函数
s1.find(s2)
:在s1字符串中查找s2,查找到返回第一个字符的位置,查找失败返回s1.npos
,这个其实是一个特别标志,也可以看成一个数字,是4294967295,即s1.npos=4294967295
#include<bits/stdc++.h>
using namespace std;
int main(){
string s = "abcdabef";
cout << s.find('b') << endl;
cout << s.find("ab") << endl;
cout << s.find("cda") << endl;
cout << s.find("cde") << endl;
return 0;
}
输出如下:
1
0
2
4294967295 // 不同的编译环境这个值可以不一样
- set集合查找
`set.find(a):查找a是否在set中,如果找不到,返回set.end()
set.count(a):本来是计算a出现的次数,但是由于集合中是没有重复元素的,于是count函数也就被作为查找函数了,因为a只能出现1次或者0次,查找成功,返回1;查找失败返回0.
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<int> v = {1,2,3,4};
set<int> s(v.begin(), v.end());
//查找2
if (s.find(2) != s.end()) cout << "查找成功" << endl;
else cout << "查找失败" << endl;
return 0;
}
- map映射查找
map.find()
:主要用于查找key是否存在map中,不存在返回map.end()
,用法和set一样.
insert(); 插入一个数,插入的数是一个pair
erase();
(1)输入是pair中的key(值), 可以删除对应的键值对
(2)输入一个迭代器,删除这个迭代器 通常是与find结合使用
find(); 查找一个数 输入参数为key值
lower_bound(x); 返回大于等于x的最小的数的迭代器 输入参数为key值
upper_bound(x); 返回大于x的最小的数的迭代器 输入参数为key值
map的遍历方法
假设有个map<int,string> s;
第一种:
for(map<string,int>::iterator it=m.begin();; it!=m.end(); it++) {
cout<<it->first<<" "<<it->second<<endl;
}
//C++中如果是个结构体(类)类型的指针,那么访问属性不能使用 . ,而是 -> 。map内部其实就是
//pair,其中first存的是被当成下标的部分,second存的是被当成值的部分。
第二种:
for(auto it:m) {
cout<<it.first<<" "<<it.second<<endl;
}//C++11的新语法
map<int, int> map;
map.insert(make_pair(1, 2));
map.insert({3, 4});
map.insert({5, 6});
map.insert({7, 8});
map.insert({11, 12});
map.insert({10, 19});
map.erase({10});
auto temp = map.find(5); //6
cout << temp->second << endl;
map.erase(temp); //删除{5, 6}
for(auto it : map){
cout << it.second << endl; //2, 4, 8, 12
}
auto it = map.lower_bound(6);
cout << it->second << endl;
// cout << it - map.begin() << endl; //这种写法无效 红黑树的map迭代器并没有重载减法运算符
unordered_map
unordered_map是一个关联容器,存储元素时是没有顺序的,只是根据key的哈希值,将元素存在指定位置,所以根据key查找单个value时非常高效,平均可以在常数时间内完成。
unordered_map内部实现了一个哈希表,因此其元素的排列顺序是杂乱的,无序的
对于unordered_map容器,其遍历顺序与创建该容器时输入元素的顺序是不一定一致的,遍历是按照哈希表从前往后依次遍历的
`不支持lower_bound()和upper_bound()
不支持迭代器
ACM模式处理不定长输入的问题
string temp; //单次读取
getline(cin, temp);
istringstream ss(temp);
vector<int> nums;
int num;
while (ss >> num) {
nums.push_back(num);
}
string temp;
while (getline(cin, temp)) { //循环读取
istringstream ss(temp);
vector<int> nums;
int num;
while (ss >> num) {
nums.push_back(num);
}
for (auto nve : nums) cout << nve << " ";
cout << endl;
}
5.字符串整形转换函数
字符串转整形
stoi(s):将字符串s转化成整形,s为string
类型,即string --> int
atoi(s):将字符串转化为整形,但s为const char*
类型,可以先用s.c_str()方法把string类型转化为const char类型,再转为整形,即const char --> int.
原因是:
atoi()的参数是 const char ,因此对于一个字符串str我们必须调用 c_str()的方法把这个string转换成 const char类型的,而stoi()的参数是const string,不需要转化为 const char*;
stringstream:需要头文件#include
using namespace std;
int main(){
string s = "124";
int a = stoi(s);
s = "123.4";
double x;
stringstream ss;
ss << s;
ss >> x;
cout << a << endl;
cout << x << endl;
return 0;
}
输出为:
124
123.4
整形转字符串
stringstream
:需要头文件#include<sstream>
,可将整形或浮点型数字转化为字符串,即int --> string, double --> string
to_string()
:可将整形转化为字符串,不推荐将浮点型转化为字符串
using namespace std;
int main(){
double x = 12.34;
int y = 12;
stringstream ss;
string s;
ss << x;
ss >> s;
cout << s << endl;
s = to_string(y);
cout << s << endl;
return 0;
}
12.34
12
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~