♥
系统分配空间耗时与空间大小无关,与申请次数有关
♥
vector
♥
支持随机寻址,即 a[i];
#include <vector> // 头文件
// 定义
vector<int> a;
vector<int> a[10];
vector<int> a(10, vector<int>(5)); // 创建二维向量
// 定义一个长度为 10 的 vector并将其中的值初始化为 3
vector<int> a(10, 3);
// 用 vector 初始化
vector<int> b(a); // 直接用 a 初始化 b
vector<int> b(a.begin(), a.begin() + 3); // 将 a 中从 0 开始 三个元素作为 b 的初始值
b = a; // 也可以直接将 a 复制到 b 中
// 用 数组 初始化
int n[] = {1, 2, 2, 4, 5};
vector<int> a(n + 1, n + 4); // 2 3 4
vector<int> b(&n[2], &n[4]); // 3 4 => 懂了,括号里要填地址 而非元素值
// a 中元素的 个数 O(1)
a.size();
// a 是否为空 O(1)
a.empty();
// 清空
a.clear();
// 返回 第一个/最后一个 元素
a.front();
a.back();
// 在最后插入一个元素 x / 删去最后一个元素
a.push_back(x);
a.pop_back();
// 在某一元素前 插入 n 个元素 x, 不填写插入个数 则默认插入一个
a.insert(a.begin() + 2, 3, 10); // => 在第三个元素前 插入 3 个10
b.insert(b.begin() + 1, a.begin() + 1, a.end()); // 在 b 第一个元素后,插入 a 中第 2 个元素到 最后一个元素
b.insert(b.begin(), n + 1, n + 5); // n 为数组
b.insert(b.begin(), &n[1], &n[5]); // 结果同上(大概)
// 删除
a.erase(a.begin()); // 删除起始位置元素
a.erase(a.begin() + 1, a.begin() + 3); // 删除 第二个位置到第三个位置的元素
// 交换
b.swap(a);
// ☆ 迭代器
a.begin(); // 起始位置
a.end(); // 最后一个元素的 后 一个位置
//遍历方法
for(int i = 0; i < a.size(); i ++ )
cout << a[i] << endl;
for(vector<int>::iterator i = a.begin(); i != a.end(); i ++ )
cout << *i << endl;
// C++ 关键字 auto 遍历, 效率稍快
for(auto x : a)
cout << x << endl;
// vector 之间可以直接比较 => 用上面的复制 测试
// 直接从下标 0 开始 按照 字典序 比较
if(a > b) puts("a > b"); // 输出 a <= b
else puts("a <= b");
♥
尽量减少申请空间的次数 => 倍增思想
每次预先开的数组长度不够时,将原先长度乘以 2 ,将之前的元素复制过来
开 2 倍更省时间,1.5 更省空间
具体看 C++ vector的动态扩容,为何是1.5倍或者是2倍
♣
长度为 n 时,申请空间的次数为 log n,且额外复制的效率约为 O(1)
♥
pair
♥
#include <iostream> // 好像写了这个就不用写 utility 了
#include <utility>
using namespace std;
// 定义
pair<Type1, Type2> p; // Type 可以是 int, char, string, long long ... vector 也行
pair<T1, pair<T2, T3> > p;// pair 也可以套娃
pair<T1, T2> p[10];
// 初始化
pair<int, string> p(1, "ab");
pair(int, string> p;
p = make_pair(10, "ab");
p = {20, "cc"};
pair<int, string> p1 = p;
// 调用成员
p.first;
p.second;
// 比较规则
// 先比较 first 中的元素,再比较 second 中的元素
// 不同组成类型的 pair 不能直接进行比较
if( p1.first < p2.first || !(p1.first > p2.first) && p1.second < p2.second)
p1 < p2;
♥
String
参考链接
♥
支持随机寻址,如 str[i];
#include <string>
// 定义
string a;
// 初始化
string a("abc");
string a(3, 'h'); // a = "hhh", 好像不能写成 (3, "h");
string a("hahaha", 2, 3); // 从下标 2 开始,长度为 3 的字符串! 3 作为长度,而非结尾下标
a = "hahah";
a = 'h';
string b = a;
// 可以直接与 字符串、字符 相加
a += "haha";
a += 'h';
// 字符串长度
a.length();
a.size();
// 比较规则 => 按照字典序
a < b; // 可直接进行比较
s1.compare(s2); // 当 s1 > s2 时,返回值大于0;
// s1 == s2时,返回值等于0;
// s1 < s2 时,返回值小于0;
s1.compare(1, 2, s2, 2, 3); // 也可以选择子串相比,s2 也可以直接使用字符串 如"Hello",
// 这里的 1, 2 表示 下标从 1 开始 长度为 2 的子串,2, 3同理
// 选取子串
s1 = "Xfd big newbee";
s2 = s1.substr(4, 3); // s2 = "big";
s2 = s1.substr(8); // s2 = "big newbee";
s2 = s1.substr(8, 100); // s2 = "big newbee";
// 交换
s1.swap(s2);
// 查找子串 => 找到了返回 子串在s1中起始位置下标;(第一次找到位置)
// 没找到则返回 string::npos
s1.find("ha");
s1.find("ha", 3); // 从下标 3 开始查找
s1.rfind("ha"); // 从后往前查找
s1.find_first_of("fd"); // 第一次出现 f 或 d 的位置
s1.find_last_of("fd"); // 最后一次出现 f 或 d 的位置
s1.find_first_not_of("fd"); // 第一次没有出现 f 或 d 的位置
s1.find_last_not_of("fd"); // 最后一次没有出现 f 或 d 的位置
// 替换子串
s1.replace(1, 3, "abaaba", 2, 4); // 用"abaaba"下标 2 开始 长度为 4 的子串,替换 s1 下标 1 开始 长度为 3 的子串
s1.replace(1, 3, 5, '0'); // 用 5 个 '0' 替换 s1 中子串
// 清空字符串
s.clear();
// 删除子串
s1.erase(1, 3); // 删除 下标 1 开始长度为 3 的子串
s1.erase(3); // 删除下标 3 及以后所有字符
// 判断是否为空
s.empty();
// ☆ 迭代器
str.begin(); // 起始位置
str.end(); // 最后一个元素的 后 一个位置
// 读取空格
getline(cin, s);
// 遍历方法
for(auto x : s1) cout << x << endl;
for(int i = 0; i < s1.size(); i ++ ) cout << x << endl;
printf("%s\n", s.c_str()); // 用 printf 输出 string 的方法
♥
queue
♥
#include <queue>
// 定义
queue<int> q;
queue<int> q[10];
// 元素个数
q.size();
// 队列是否为空
q.empty();
// 向队尾插入元素 x
q.push(x);
// 返回队头 / 队尾 元素
q.front();
q.back();
// 弹出队头元素
q.pop();
// 清空队列 => 没有 clear ,直接重新定义一下
q = queue<int>();
♥
priority_queue
♥
靠 堆 实现
#include <queue>
#include <vector> // 定义小根堆的时候需要
// 定义
priority_queue<Type> q; //默认大根堆
priority_queue<Type> q[10];
priority_queue<int, vector<int>, greater<int> > q; // 小根堆
// 插入一个元素
q.push();
// 返回堆顶元素
q.top();
// 弹出堆顶元素
q.pop();
// 判断是否为空
q.empty();
// 返回队内元素个数
q.size();
// 交换
q.swap(q1);
// 自定义排序规则
// 方式 1
struct node // 运算符重载 <
{
int x;
bool operator < (const node &t) const
{
return x > a.x; // 小顶堆
}
};
priority_queue<node> q;
// 方式 2
struct node2
{
bool operator() (T1 a, T1 b)
{
return a.x > b.x; // 小顶堆
}
}
priority_queue<T1, vector<T1>, node2> q;
典中典,看病要排队(HDU炸了,想起来再补)
♥
stack
♥
#include <stack>
// 定义
stack<Type> s;
// 向栈顶插入一个元素
s.push();
// 返回栈顶元素
s.top();
// 弹出栈顶元素
s.pop();
// 查询栈中元素个数
s.size();
// 判断栈是否为空
s.empty();
♥
deque
♥
效率超慢
支持随机寻址 q[i]
#include <deque>
// 定义
deque<Type> q;
// 查询大小
q.size();
// 判断是否为空
q.empty();
// 清空
q.clear();
// 查询队头 / 队尾 元素
q.front();
q.back();
// 插入 x
push_front(x); // 向队头插入
push_back(x); // 向队尾插入
// 弹出
pop_front(); // 弹出队头元素
pop_back(); // 弹出队尾元素
// ☆ 迭代器
q.begin();
q.end();
♥
set / multiset
♥
不能含有重复元素
multiset 可以含有重复元素
#include <set>
// 定义
set<Type> s;
multiset<Type> ms;
// 插入一个元素 x
s.insert(x);
// 查找一个元素 x => 查找失败 返回 s.end();
s.find(x);
// 返回某个元素的个数
s.count(x);
// 查询元素个数
s.size();
// 判断 set 是否为空
s.empty();
// 清空
s.clear();
// 删除 x
s.erase(x); // 删除所有 x O( k + logn)
s.erase(find(x)); // 也可以删除一个迭代器
// unordered_set / unordered_multyset 不支持该操作
// 不存在的话 返回 s.end()
lower_bound(x); // 返回大于 等于! x 的最小的数 的迭代器
upper_bound(x); // 返回大于 x 的最小的数 的迭代器
set<int> s;
int p = *s.upper_bound(x);
cout << p << endl;
♥
map / multimap
♥
支持随机寻址 , 时间复杂度 O(log n)
也支持 upper_bound 和 lower_bound
#include <map>
//定义
map<Type1, Type2> mp;
// 插入
map<string, int> mp;
mp.insert("abc", 1);
mp["abc"] = 1;
// 删除
// 迭代器删除
mp.erase(mp.find("abc"));
// 关键字删除
mp.erase("abc"); // 删除成功返回 1,否则返回 0
// 迭代器 范围删除
mp.erase(mp.begin(), mp.end()); // 等同于 clear()
// 清空
mp.clear();
♥
unordered_…
♥
unordered_set, unordered_map, unordered_multiset, unordered_multimap
它的内部是无序的(我也不知道能不能遍历。。)
除了不能用 upper_bound 和 lower_bound ,迭代器++ ,- -,之外,基本操作都与上面类似
但 增删改查的时间复杂度为 O(1);