STL容器
一、顺序容器 顺序容器的元素排列次序与元素值无关
vector/deque/list/forward_list/array/string
二、关联容器 顺序容器的元素排列次序与元素值有关
有序容器:set/multiset/map/multimap -----红黑树
无序容器:unordered set/unordered multiset/unordered map/unordered multimap ----- 哈希表
三、STL容器适配器 以既有的容器为底部结构,改变接口
stack/queue/priority_queue
vector
可变大小数组;
支持快速随机访问;
在尾部之外的位置插入和删除元素可能很慢;
两个重要方法:
erase:返回迭代器指向被删除元素的下一个元素
iter = v.erase(iter);
// vector删除
vector<int> v1 = {2, 5, 3, 4, 5, 5, 2, 2, 0, 4};
// 删除所有的5
for (auto iter = v1.begin(); iter != v1.end();) {
if (*iter == 5) {
v1.erase(iter); // 或者 iter = v1.erase(iter);
} else {
++iter;
}
}
for_each(v1.begin(), v1.end(), [](int i){ cout << i << ","; });
insert:返回迭代器指向插入的元素
// vector插入
vector<int> v2 = {2, 5, 3, 4, 5, 5, 2, 2, 0, 4};
// insert 6 before every 5
for (auto iter = v2.begin(); iter != v2.end(); iter++) {
if (*iter == 5) {
iter = v2.insert(iter, 6);
++iter; // 此时iter指向6, ++后指向5, 在for中++后指向5的下一个元素
}
}
for_each(v2.begin(), v2.end(), [](int i){ cout << i << ","; });
deque
双向开口,双向进出;
动态分段连续空间组合而成,不存在vector那样因空间不足重新配置,导致元素大量赋值的问题
支持随机访问,访问效率远大于vector
首尾删,指针都不会失效;
首尾增,可能导致管控中心map重新配置,指针不会失效,但是迭代器失效
中间删,需要保证连续性,会造成前面或者后面所有指针失效;
中间增,若导致map重新配置,会造成指针有效但是迭代器失效
string
定义如下:
/// A string of @c char
typedef basic_string<char> string;
array
固定大小的数组,比原生数组的功能多
array<int, 5> arr1 = {1, 2, 3, 4, 5};
auto arr2 = arr1; // array支持复制
try {
cout << arr1.at(5) << endl; // at函数支持越界检查
} catch(exception &e) {
cout << e.what() << endl;
}
std::sort()
只有随机访问迭代器才可以使用sort()/stable_sort()
前向迭代器++ forward_list 快速排序 归并排序
后向迭代器- 堆排序 插入排序
双向迭代器 ++ -- list map set 插入排序
随机迭代器++ -- +n -n vector deque string array 原生数组
#include <iostream>
#include <list>
#include <algorithm>
int main()
{
list<int> l = {5, 4, 3, 2, 1};
l.sort(); // list排序只能使用sort(),不能使用stable_sort()
for_each(l.begin(), l.end(), [](int i){ cout << i << ",";});
return 0;
}
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
int arr[] = {5, 4, 3, 2, 1};
string str("Hello World");
sort(arr, arr + 5);
stable_sort(str.begin(), str.end());
int len = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < len; i++) {
cout << arr[i] << ", ";
}
cout << endl;
for_each(str.begin(), str.end(), [](char i){ cout << i << ",";});
return 0;
}
list
双向循环链表,不支持随机访问,插入删除效率高
增删节点后,只需要修改指针,所有元素的位置都不变,所以迭代器都没失效
但是遍历删除的时候,需要小心
前置的++返回引用;后置++返回临时变量
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
int main()
{
list<int> l1 = {2, 5, 3, 4, 5, 5, 2, 2, 0, 4};
// delete all 5
for (auto iter = l1.begin(); iter != l1.end();) {
if (*iter == 5) {
// list删除时需要iter++,否则执行错误
l1.erase(iter++); // 或者iter = l1.erase(iter);
} else {
++iter;
}
}
for_each(l1.begin(), l1.end(), [](int i){ cout << i << ", ";});
cout << endl;
vector<int> v1 = {2, 5, 3, 4, 5, 5, 2, 2, 0, 4};
// 删除所有的5
for (auto iter = v1.begin(); iter != v1.end();) {
if (*iter == 5) {
v1.erase(iter); // 或者iter = v1.erase(iter);
} else {
++iter;
}
}
for_each(v1.begin(), v1.end(), [](int i){ cout << i << ", "; });
return 0;
}
set/map
元素并非连续存放,插入删除时原有的迭代器都不会失效,操作方式同list;
元素位置和key值强相关,key值不可修改;
自定义类型作为key时,需要重载operator <;
a < b 和b <a 都是false的时候需要重构operator==;
#include <iostream>
#include <set>
#include <algorithm>
struct C1 {
int data;
// 运算符重载
bool operator< (const C1 &c1) const
{
return data < c1.data;
}
};
int main(int argc, const char *argv[])
{
using namespace std;
C1 c1[5] = {5, 4, 3, 2, 1};
set<C1> s;
for (auto e : c1) {
s.insert(e);
}
cout << "iter->data: ";
for (auto iter = s.begin(); iter != s.end(); iter++) {
cout << iter->data << ",";
}
return 0;
}
unordered_set/unordered_map
无序容器,底层结构 ---- 哈希表
无排序功能,插入和查找效率高于set/map
对于自定义类型,需要重载operator==,并提供哈希函数(基本类型以及string,系统都已经内置)
stack,queue
不是真实的容器,是对某种底层容器封装的适配器,默认底层容器是deque,也可以是vector,list或者其他符合要求的容器
stack和queue都不支持遍历操作,也没有相应的迭代器
priority_queue 优先队列/堆
priority也是适配器,默认底层容器是vector,支持的函数和queue一样,只是出队规则不同
内部元素并非按照入队先后排列,而是按照一定的权值排列,priority本质上是堆
因为堆调整需要随机访问能力,所以底层容器必须有随机访问迭代器
找出数组中最大的元素 ----->找出数组中第k大的元素
优先队列求解复杂度:O(n.logk)
其他方法:
排序求解复杂度:O(n.longn)
用普通数组保存前k,复杂度:O(n.k)
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
// 输出第k大的数字
void topK(const vector<int> &v, int k)
{
priority_queue<int, vector<int>, std::greater<int>> p;
for (const auto e : v) {
p.push(e); // 从小到大入队
if (p.size() > k) { // 维持大小为k的优先队列,如果队列大于k,将最先入队的弹出
p.pop();
}
}
cout << p.top() << endl; // 队头显示的就是第k大的
}
int main()
{
vector<int> v2 = {2, 5, 3, 4, 5, 5, 2, 2, 0, 4};
sort(v2.begin(), v2.end());
for_each(v2.begin(), v2.end(), [](int i){ cout << i << ", "; });
cout << endl;
int k = 7;
topK(v2, k);
return 0;
}