内容提要
STL
STL
首先,拒绝两个问题:
- 这东西我自己也能写吖
- 这东西怎么写吖(比如STL的sort是七八个排序放一块的...)
Pair
#include<utility> using namespace std; pair<typename1,typename2> variablename; pair<int,int> x; pair<double ,double> y; pair<int,double> z; pair<pair<int,int>int>a;
作为需要返回多个量的函数返回值
作为结构体的代替
比较大小:先比较第一个元素,如果相同再比较第二个,以此类推
String
string a;
#include <string> using namespace std; string a;
作为字符串数组的替代
可以赋值
a = b,a = "hello word"
a[i]:支持下表访问
a.size()字符串长度
a+b:字符串拼接
vector
有编号为1到3000*3000的人,每个人都属于一个队伍,一共有3000个队伍,每个队伍可能有任意多数人,也可能没有人,如何存数?
const int maxN = 3000; const int maxM = 3000 * 3000; int team[maxN][maxM];
vector:不定长数组:不需要指定数组元素的数量,可以直接通过元素的个数分配内存
#include <vector> using namespace std; vector<TypeName> VariableName; vector<int> a; vector<double> b; vector<vector<int> > c;
a[0]:随机下标访问
a.push_back():在末尾插入一个元素
a.pop_back:弹出末尾元素
a.front():访问第一个元素
a.back():访问最后一个元素
a.clear():清空一个vector
a.empty():返回vector是否为空
a.size():返回vector总元素的个数
以上的除了清空vector复杂度为O(n),其他均为O(1)
工作原理:每当你添加第2^n +1个元素时,就开一个连续的2^(n+1)的内存来存储
但是由于他每次要分配内存,所以会慢一些
样例:接受n个整数的输入,倒序输出
#include <iostream> using namespace std; int main() { vector<int> a; int n, x; cin >> n; for (int i = 0; i < n; ++i) { cin >> x; a.push_back(x); } while (!a.empty()) { cout << a.back(); a.pop_back(); } return 0; }
迭代器
vector<int>::iterator it;
迭代器(iterator)的作用类似于指针,是一个指明元素位置的量。什么类型的vector就要用什么位置的迭代器
a.begin():返回第一个元素的迭代器
a.end():返回最后一个元素的后一个迭代器(因为左闭右开嘛)
*a.begin():等价于a.front()
*it:得到it指向的值
it++:得到下一个位置的迭代器
it+=i:得到下i个位置的迭代器,时间复杂度O(1)
it1 - it2:得到it1和it2之间的元素个数
遍历vector:
int main() { for(auto x:a) { } //遍历 }
set:
集合:不能有重复元素+有序性
#include <set> using namespace std; set<TypeName> VariableName; set<int> a; set<double> b;
set的底层使用红黑树这个数据结构来维护集合
a.begin():第一个元素的迭代器
a.end():最后一个元素的后一个迭代器
a.insert():插入一个元素 O(log n)
a.erase():删除一个元素 O(log n)
a.find():寻找一个元素 O(log n)
a.count():查找某个元素的数量 O(log n)
a.lower_bound():查找大于等于某个值的第一个元素 O(log n)
a.upper_bound():查找大于某个值的第一个元素 O(log n)
a.equal_range():查找等于某个值的左闭右开区间,返回一个pair O(log n)
#include <set> #include <iostream> using namespace std; int main() { set<int> a; a.insert(1); // a: {1} a.insert(1); // a: {1} a.insert(2);remove: {1, 2} a.erase(1); // a: {2} for (int i = 0; i < 5; ++i) { a.insert(i); } // a: {0, 1, 2, 3, 4} cout << a.size() << endl; // 5 cout << a.count(4) << endl; // 1 }
Set 的迭代器和 Vector 的不同。
set<int>::iterator it;
• *it: it 的求值
• ++it: it 的下一个迭代器
• --it: it 的前一个迭代器
• Vector: 随机访问迭代器
• Set: 双向迭代器
它并不滋兹减法
重载运算符:
struct Student { int grade; char name[20]; } bool operator <(Student a, Student b) { return a.grade < b.grade; }
或者也可以这么写
struct Student { int grade; char name[20]; bool operator <(Student b) { return grade < b.grade; } }
MultiSet
#include <set> using namespace std; multiset<TypeName> VariableName; multiset<int> s;
multiset 和 set 大部分操作相同,但支持在一个 set 内有多个元素。
注意在 multiset 中,如果 erase 一个数,仍然会把全部的数字删除。
Map
Problem
给出许多学生的名字和成绩,要求使用名字找到成绩。
比如学生 __debug 的微积分 59 分,我们希望能通过 __debug 找到 59.
a['__debug'] = 59 ?
#include <map> using namespace std; map<TypeName1, TypeName2> VariableName; map<string, int> a;
map 的本质就是一个元素为 pair 的 set,重载了 [] 运算符。
stack栈
#include <stack> using namespace std; stack<TypeName> VariableName; stack<int> a;
一个“先进后出”结构。
a.size()
a.empty()
a.top(): 访问栈顶元素
a.pop(): 弹出栈顶
a.push(): 压入一个元素
queue队列
#include <queue> using namespace std; queue<TypeName> VariableName; queue<int> a;
一个“先进先出”结构。
一个类似队列的结构。不同的是,队列每次出最先进队的元素,优先队列每次出最大的元素
类似 Set,需要重载 < 运算符
a.size()
a.empty()
a.top(): 访问堆顶
a.pop(): 弹出堆顶
a.push(): 向堆中加入一个元素
当然也可以不用
priority_queue<int ,vector<int>,less<int> > q;//大根堆 priority_queue<int ,vector<int>,greater<int> > q;//小根堆
或者这样
struct cmp { bool operator()(int x,int y) { return x<y; } } priority_queue<int ,vector<int>,cmp > q;
Algorithm
Sort
#include <algorithm> using namespace std; int a[30]; vector<int> b; int main() { sort(a, a + 30); sort(b.begin(), b.end()); }
Reverse
#include <algorithm> using namespace std; int a[30]; vector<int> b; int main() { reverse(a, a + 30); reverse(b.begin(), b.end()); }
unique
去重(必须要是排序好了的数列)
fill(把头到尾覆盖某个数)
int main { sort(a,a+10); for(int i=0;i<10;i++) cout<<a[i]<<" "; cout<<endl; fill(unique(a,a+10),a+10,0) for(int i=0;i<10;i++) cout<<a[i]<<" "; }
Next Permutation
int a[4] = {1, 2, 3, 4};
int main() { do { for(int i=0;i<4;++i) cout<<a[i]<<" "; cout<<endl; }while(next_permutatiom(a,a+4)); }
寻找全排列
要求数组中元素可以比较。
均摊复杂度 O(1),单次运算交换次数不超过distance(Ai; Ai+1)/2, Ai; Ai+1 分别为第 i, i + 1 个排列,但是如果列出全排列的话就是O(n!)
Nth Element
#include <iostream> #include <vector> #include <algorithm> #include <functional> int main() { std::vector<int> v{5, 6, 4, 3, 2, 6, 7, 9, 3}; std::nth_element(v.begin(), v.begin() + v.size()/2, v.end()); std::cout << "The median is " << v[v.size()/2] << ' '; std::nth_element(v.begin(), v.begin()+1, v.end(), std::greater<int>()); std::cout << "The second largest element is " << v[1] << ' '; }
复杂度O(n)
只让中间那个放在正确的位置,比他大的在前面,比他小的在后面
Random Shuffle
#include <random> #include <algorithm> #include <iterator> #include <iostream> int main() { std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; std::shuffle(v.begin(), v.end(), g); }