文章目录
1 二元组:pair
pair<int, string> p, p1, p2;
p.first // 第一个元素(int)
p.second // 第二个元素(string)
p1 = make_pair(1, "2"); // 构造pair
p2 = {3, "4"}; // 构造pair(c++11)
// 支持比较运算,先按first排,再按second排
p1 < p2
pair<int, pair<int, int>> pp; // 三元组
2 变长数组:vector
采用倍增的思想,当元素个数超过大小时,将大小*2。
例如分配
1
0
3
10^3
103空间
那么第一次分配空间大小为:1
第二次分配空间大小为:2
第三次分配空间大小为:4
第四次分配空间大小为:8
…
第10次分配空间大小为:512
总共大小:
1
+
2
+
4
+
.
.
.
+
512
=
1023
1 + 2 + 4 + ... + 512=1023
1+2+4+...+512=1023
#include <iostream>
using namespace std;
#include <vector>
int main(){
vector<int> a; // 定义一个vector
vector<int> a(10); // 长度为10的vector
vector<int> a[10]; //同上
vector<int> a(10, 3); // 长度为10的vector,且每个数都是3
//二维vector,大小是[10][100],初始化全为-0x3f3f3f3f
vector< vector<int> > a(10, vector<int>(100, -0x3f3f3f3f));
vector<int> a = {1, 2, 3, 4, 5}; // 定义一个vector,并给初始值
// 遍历vector(其他set、map也可用)
for (auto x : a) cout << x << endl; // (c++11才可用auto)
for (vector<int>::iterator i = a.begin(); i != a.end(); i ++ ) cout << *i << endl;
for (int i = 0; i < a.size(); i ++ ) cout << a[i] << endl; // 用[]是vector特有的
a.size(); // 返回元素个数 时间O(1)
a.empty(); // a为空返回true 时间O(1)
a.clear(); // 清空a
a.front(); // 返回a第一个数
a.back(); // 返回a最后一个数
a.push_back(1); // 向a末尾插入1
a.pop_back(); // 删除a末尾的数
a.resize(5); // 将a大小改成5
a.assign(6, 9); // 给a赋值成6个9
vector<vector<int>> b;
b.assign(3, vector<int>(4, 1)); // b赋值成3 * 4的矩阵,每个值是1
// 支持比较,按字典序比较,3333 < 444
vector<int> b(4, 3); // 4个3
vector<int> c(3, 4); // 3个4
if (b < c) printf("b < c");
}
3 字符串:string
string a = "abc"; // 创建字符串
a += "def"; // 末尾添加字符串
a.size(); // 返回元素个数 时间O(1),也可用a.length()
a.empty(); // a为空返回true 时间O(1)
a.clear(); // 清空a
a.substr(1, 2); // 从下标1开始,长度为2的子串:bc
a.substr(1, 200); // 超过长度则会输出到最后一个字母:bcdef
a.substr(1); // 输出到最后一个字母:bcdef
printf("%s\n", a.c_str()); // c_str()返回a的起始地址
a = to_string(-123); // int转string
int l1 = stoi(a); // string转int
long l2 = stol(a); // string转long
long long l3 = stoll(a); // string转long long
4 队列:
4.1 queue 普通队列
#include <queue>
queue<int> a;
a.size(); // 返回元素个数 时间O(1)
a.empty(); // a为空返回true 时间O(1)
a = queue<int>(); // 队列没有clear,构造新的来清空
a.front(); // 返回队头
a.back(); // 返回队尾
a.push(1); // 向队头插入
a.pop(); // 队尾弹出
4.2 priority_queue 优先队列
用堆实现
#include <queue>
priority_queue <int> a; // 默认大根堆
// 插入x时改成-x,可变成小根堆
// 定义小根堆,参数分别是堆存的元素类型、堆实现方式(一般都是vector)、比较方式
priority_queue <int, vector<int>, greater<int>> b;
a.size(); // 返回元素个数 时间O(1)
a.empty(); // a为空返回true 时间O(1)
a = priority_queue <int>() // 队列没有clear,构造新的来清空
a.top(); // 返回堆顶
a.push(1); // 向堆插入
a.pop(); // 弹出堆顶
template <class T> struct greater {
bool operator() (const T& x, const T& y) const {return x>y;}
typedef T first_argument_type;
typedef T second_argument_type;
typedef bool result_type;
};
与之相对的是less
template <class T> struct less {
bool operator() (const T& x, const T& y) const {return x<y;}
typedef T first_argument_type;
typedef T second_argument_type;
typedef bool result_type;
};
4.3 deque 双端队列
功能强大但效率很低
#include <deque>
deque<int> a;
a.size(); // 返回元素个数 时间O(1)
a.empty(); // a为空返回true 时间O(1)
a.clear() // 清空a
a.front() // 返回第一个元素
a.back(); // 返回最后一个元素
a.push_back(1) // 队尾插入元素
a.pop_back() // 队尾删除元素
a.push_front(1); // 队首插入元素
a.pop_front(); // 队首删除元素
a[1]; //支持[]取元素
a.begin();
a.end();
5 栈:stack
#include <stack>
stack <int> a;
a.size(); // 返回元素个数 时间O(1)
a.empty(); // a为空返回true 时间O(1)
a = stack<int>() // 栈没有clear,构造新的来清空
a.top(); // 返回栈顶
a.push(1); // 栈顶插入
a.pop(); // 栈顶弹出
6 红黑树(平衡二叉树):
6.1 set
不能有重复元素,插入重复元素将忽略
#include <set>
set<int> a;
a.size(); // 返回元素个数,时间O(1)
a.empty(); // a为空返回true,时间O(1)
a.clear(); // 清空a
a.insert(1); // 插入一个数,时间O(log(n))
a.find(1); // 查找一个数,不存在返回a.end()
a.count(1); // 返回某个数的个数
a.erase(1); // 删除所有等于1的结点,时间O(k + logn)
//a.erase(迭代器); // 删除迭代器
a.insert(1);
a.insert(2);
a.insert(3);
for (auto it : a) { // c++11中可以用auto快速遍历
cout << it << " "; // 目前set里有1, 2, 3
}
cout << endl;
set<int>::iterator it;
int x = 2;
it = a.lower_bound(x); // 返回>=x的第一个数的迭代器
cout << *it << endl; // 2
it = a.upper_bound(x); // 返回>x的第一个数的迭代器
cout << *it << endl; // 3
6.2 map
#include <map>
map<string, int> a;
a.size(); // 返回元素个数,时间O(1)
a.empty(); // a为空返回true,时间O(1)
a.clear(); // 清空a
a.insert({"a", 1}); // 插入一个pair,时间O(log(n)),重复会忽略
a["b"] = 2; // 支持[]来插入元素,时间O(log(n)),重复会覆盖
if(a["b"] == 2); // 支持[]来通过key找value,时间O(log(n))
for (auto it : a) { // c++11中可以用auto快速遍历,这边的it是pair变量,不是迭代器
cout << it.first << " " << it.second << endl; // first是key,second是value
}
cout << endl;
map<string, int>::iterator it;
it = a.find("a"); // 查找一个pair,不存在返回a.end(),存在返回pair{"a", 1}的地址
cout << it->first << " " << (*it).second << endl; // 输出key和value: a 1
a.count("a"); // 返回key="a"的个数
a.erase("a"); // 删除所有key="a"的结点,时间O(k + logn)
// a.erase(迭代器); // 删除迭代器 例如a.erase(a.begin())删除第一个
a.lower_bound("a"); // 返回key>="a"的第一个迭代器
a.upper_bound("a"); // 返回key>"a"的第一个迭代器
it = a.lower_bound("b");
cout << it->first << endl; // 上面erase了a,map里只剩b,所以这边使用 lower_bound能查找到b("b"),如果使用 upper_bound("b")则会报错
//
unordered_map<int, int> map1;
map1[0] = 0;
map1[1] = 1;
unordered_map<int, int> map2;
map2[1] = 1;
map2[0] = 0;
if (map2 == map1) { // 可以直接比较,但只能用==,不能用<或>
cout << "相等" << endl;
}
6.3 multiset
可以用重复元素
其他操作同set
6.4 multimap
可以用重复元素
其他操作同map
7 哈希表:
和上面操作一样,但增删改查时间是O(1)
不支持lower_bound()和upper_bound()
不支持迭代器的++、–
7.1 unordered_set
7.2 unordered_map
7.3 unordered_multiset
7.4 unordered_multimap
7.5 手写哈希值
遇上没法比较的对象,需要手写哈希值。
struct ptrCmp
{
bool operator()(const char * s1, const char * s2) const {
return strcmp(s1, s2) == 0;
}
};
struct ptrHash
{
size_t operator()(const char *str) const {
size_t strLength = strlen(str);
size_t hash = std::_Hash_impl::hash(str, strLength);
return hash;
}
};
unordered_map<char *, int, ptrHash, ptrCmp> mp;
8 压位:bitset
bool flag[1024];需要1024字节
如果压到位里,因为每位是8位,只需要128字节。
#include <bitset>
bitset<10000> a; // 大小10000的bitset
// 支持以下操作
~, &, |, ^
>>, <<
==, !=
[]
a.count(); // 返回多少个1
a.any(); // 判断是否至少有1个1
a.none(); // 判断是否全为0
a.set(); // 把所有变成1
a.set(k, v); // 第k位变成v
a.reset(); // 所有变成0
a.flip(); // 所有位取反
a.flip(k); // 第k位取反
9. sort
#include <algorithm>
using namespace std;
struct Node {
int l, r;
bool operator< (const Node &p) const //自定义比较函数
{
//按照r从小到大排序,r相等按l从大到小排序
if(r != p.r) return r < p.r;
else return l > p.l;
}
};
Node p[1005];
int main() {
sort(p, p + n);
}
#include <algorithm>
using namespace std;
struct Node
{
int l, r;
};
Node p[1005];
bool cmp(const Node &x, const Node &y) {
return (x.r < y.r|| (x.r == y.r && x.l > y.l));
}
int main() {
sort(p, p + n, cmp);
}
vector<int>input = { 1, 5, 2, 1, 3, 2, 5 };
//排序整个vector
sort(input.begin(), input.end());
//对任意区间进行排序,同样使用迭代器
auto start = input.begin()+2;//下标对应2
auto end = start +3;//下标对应5
sort(start, end);//区间[2,5)进行排序
10.二分
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 自定义规则,数组从大到小
class my_comp {
public:
bool operator()(const int& i, const int& j) {
return i > j;
}
};
int main() {
int a[5] = {1,3,5,7,9};
//从 a 数组中找到第一个 >= 3 的元素,如果所有元素都小于3,则返回数组末尾的后一个位置,该位置是越界的。
int *l = lower_bound(a, a + 5, 3);
int index_l = lower_bound(a, a + 5, 3) - a;
cout << *l << " " << index_l << endl; // 3 1
//从 a 数组中找到第一个 > 3 的元素
int *u = upper_bound(a, a + 5, 3);
int index_u = upper_bound(a, a + 5, 3) - a;
cout << *u << " " << index_u << endl; // 5 2
// 自定义排序方式,并在vector中搜索
vector<int> v{9, 7, 5, 3, 1}; // 递减序列
vector<int>::iterator iter = lower_bound(v.begin(), v.end(), 7 , my_comp());
int index = lower_bound(v.begin(), v.end(), 7 , my_comp()) - v.begin();
cout << *iter << " " << index ; // 7 1
}