一.时空复杂度
(一)语句(基本单位)
(二)语句执行次数(反映程序的运行时间)
1.T(x, y,⋯):语句数
2.注意循环中语句的次数
(三)时间复杂度(衡量程序效率/语句执行次数T的化简结果)
1.T->O(f)化简规则:常数->1;各项系数化为1;只保留最高阶的项;loga n 应化为 log n(即算法的运行时间与输入规模n的对数成正比)

2.时间复杂度(最大时间复杂度)的分类
(1)最大(坏)时间复杂度O(f)
(2)最小(好)时间复杂度Ω(f)
(3)精确时间复杂度Θ(f)
(四)空间复杂度(衡量程序内存占用/变量定义次数的化简结果)
记号和化简规则与时间复杂度完全相同。
二.C++ STL(标准模板库)常用组件
(一)pair:二元组(不同类型或相同类型)
#include <iostream>//引入 C++ 的标准输入输出流头文件,用于使用 std::cout 进行输出操作。
#include <utility>//引入 utility 头文件,这个头文件中包含了 std::pair 模板类的定义。
int main() {
// 创建一个 std::pair 类型的对象 p1,它包含一个 char 类型和一个 double 类型的数据
std::pair<char, double> p1 = {'x', 2.5};
// 创建一个嵌套的 std::pair 类型的对象 p2,它的第一个元素是 int 类型,第二个元素是另一个 std::pair(即 p1)
std::pair<int, std::pair<char, double>> p2 = {1, p1};
// 输出 p2 的第一个元素,即 int 类型的值 1
std::cout << p2.first << ' ';
// 输出 p2 的第二个元素中的第一个元素,即 p1 的第一个元素,是 char 类型的 'x'
std::cout << p2.second.first << ' ';
// 输出 p2 的第二个元素中的第二个元素,即 p1 的第二个元素,是 double 类型的 2.5
std::cout << p2.second.second << ' ';
return 0;
}
1 x 2.5
(二)stack:栈(只允许在栈顶进行插入和删除操作)
top() :返回栈顶元素 O(1)
empty():返回是否为空 O(1)
size() :返回元素个数 O(1)
#include <iostream>
#include <stack>//引入 C++ 的 stack 头文件,用于使用 std::stack 容器类。
int main() {
//创建一个存储 int 类型元素的栈 s
std::stack<int> s;
//向栈 s 中依次压入元素 1、2、3、4 和 5。
//元素的入栈顺序决定了它们在栈中的存储顺序。
s.push(1);
s.push(2);
s.push(3);
s.push(4);
s.push(5);
// 此时栈 s 中的元素顺序为:{1, 2, 3, 4, 5(top)},栈顶元素为 5
s.pop();
// 弹出栈顶元素 5,此时栈 s 中的元素顺序为:{1, 2, 3, 4(top)}
//注意:pop 操作只会移除元素,而不会返回被移除元素的值
while (! s.empty()) {
// 当栈不为空时,进入循环
std::cout << s.top() << ' ';//返回栈顶元素但不移除它
s.pop();//将栈顶元素从栈中移除/弹出
}
// 最终栈 s 中的元素被全部弹出,s = {},即栈为空
return 0;
}
4 3 2 1
(三)queue:队列(只允许在队尾插入元素,在队头删除元素)
front():返回队头元素 O(1)
#include <iostream>
#include <queue>//这是 C++ 标准库中的队列(queue)容器的头文件,它允许我们使用 std::queue 容器类
int main() {
// 声明一个存储 int 类型元素的队列 q
std::queue<int> q;
// 向队列中添加元素 1
q.push(1);
// 向队列中添加元素 2
q.push(2);
// 向队列中添加元素 3
q.push(3);
// 向队列中添加元素 4
q.push(4);
// 向队列中添加元素 5
q.push(5);
// 此时队列 q 的元素顺序为:{1(front), 2, 3, 4, 5(back)}
q.pop();
// 此时队列 q 的元素顺序为:{2(front), 3, 4, 5(back)}
while (! q.empty()) {
std::cout << q.front() << ' ';//返回队首元素但不移除它
q.pop();//将队首元素移除
}
// 最终队列 q 为空,即 q = {}
return 0;
}
2 3 4 5
(四)priority_queue:优先队列(会自动排序但其内部元素不可见,只允许访问最大的元素)
#include <iostream>
#include <queue>
int main() {
// 创建一个存储 int 类型元素的优先队列 pq
std::priority_queue<int> pq;
// 向优先队列中依次插入元素 3、1、2
pq.push(3);
pq.push(1);
pq.push(2);
// 此时优先队列 pq 中的元素顺序为:{1, 2, 3(top)},堆顶元素为 3
while (! pq.empty()) {
// 当优先队列不为空时,进入循环
std::cout << pq.top() << ' ';
// 输出堆顶元素
pq.pop();
// 弹出堆顶元素
}
// 最终优先队列 pq 中的元素被全部弹出,pq = {},即队列为空
return 0;
}
3 2 1
(五)vector:动态数组(能根据需要自动扩容,也能手动调整容量)
1.定义和初始化:
std::vector<float> dq1;
// dq1 = {}
std::vector<int> dq2 = {1, 1, 4, 5, 1, 4};
// dq2 = {1, 1, 4, 5, 1, 4}
std::vector<double> dq3(4, 0.5);
// dq3 = {0.5, 0.5, 0.5, 0.5}
#include <iostream>
#include <vector>//动态数组头文件
int main() {
// 创建一个大小为 4 的 vector,元素初始化为 3
std::vector<int> vec(4, 3);
// 此时 vec = {3, 3, 3, 3}
vec.push_back(6);
vec.push_back(9);
// 向 vector 末尾添加元素 6 和 9,vec = {3, 3, 3, 3, 6, 9}
vec[2] = 1;
// 将 vec 的第 3 个元素(下标为 2)修改为 1,vec = {3, 3, 1, 3, 6, 9}
vec.pop_back();
// 移除 vector 末尾的元素,vec = {3, 3, 1, 3, 6}
for (int el : vec) {
std::cout << el << ' ';
}
// 使用范围 for 循环输出 vector 中的元素
return 0;
}
3 3 1 3 6
(六)deque:双端队列(相较于 vector 增加了在头部的插入、删除操作)
1.定义和初始化:
std::deque<float> dq1;
// dq1 = {}
std::deque<int> dq2 = {1, 1, 4, 5, 1, 4};
// dq2 = {1, 1, 4, 5, 1, 4}
std::deque<double> dq3(4, 0.5);
// dq3 = {0.5, 0.5, 0.5, 0.5}
assign(count, value) 初始化为 count 个 value O(n)
at(pos) 返回第 pos 个元素 O(1)
operator [pos] 返回第 pos 个元素 O(1)
front()返回第一个元素 O(1)
#include <iostream>
#include <deque>
int main() {
std::deque<int> dq(2, 3);// dq = {3, 3}
dq.push_back(6);
dq.push_back(9);// dq = {3, 3, 6, 9}
dq.push_front(0);
dq.push_front(-1);// dq = {-1, 0, 3, 3, 6, 9}
dq[2] = 1;// dq = {-1, 0, 1, 3, 6, 9}
dq.pop_back();// dq = {-1, 0, 1, 3, 6}
dq.pop_front();// dq = {0, 1, 3, 6}
for (int el : dq) {//运用范围for循环遍历队列dq中的每个元素
std::cout << el << ' ';//把每个元素输出到控制台,元素间用空格分隔
}
return 0;
}
0 1 3 6
(七)list:链表(支持在任意位置插入和删除元素,但不支持随机访问->对于 list 的两个迭代器 p1 和 p2 ,不能用 p1 - p2 计 算它们的距离,必须使用 std::distance(p1, p2) ;O(n))
1.定义和初始化:
std::list<int> l1;
// l1 = {}
std::list<int> l2 = {1, 2, 3, 4, 5};
// l2 = {1, 2, 3, 4, 5}
#include <iostream>
#include <list>
int main() {
std::list<int> l = {1, 2, 3, 4, 5};
auto pos = l.begin();
// 获取头部迭代器
advance(pos, 2);
// 使迭代器前进两步
l.insert(pos, -1);
// l = {1, 2, -1, 3, 4, 5}
for (int el : l) {
std::cout << el << ' ';//在每次循环迭代时,el 会被赋值为 dq 容器里的一个元素,
//这里将该元素输出到控制台
}
return 0;
}
1 2 -1 3 4 5
(八)set:集合(插入其中的每种元素都只保留其一,并自动升序排序。不支持随机访问->对于 set 的两个迭代器 p1 和 p2 ,不能用 p1 - p2 计算 它们的距离,使用 std::distance(p1, p2) ;O(n))
1.分类:set、multiset(多重集:相同的元素允许存在多个。其余功能与 set 一致)、unordered_set(功能与 set 一致,但时间复杂度有所区别)。
2.定义与初始化
std::set<int> s1;
13
// s1 = {}
std::set<char> s2 = {'a', 'p', 'p', 'l', 'e'};
// s2 = {'a', 'e', 'l', 'p'}
(九)map:映射(相当于 [] 内可填任意键值任意类型对象的数组)
1.分类:map、unordered_map(功能与 map 一致,但时间复杂度有所区别)
2.定义与初始化:
std::map<int, int> m1;
15
// m1 = {}
std::map<char, int> m2 = { {'a', 3}, {'b', 2}, {'c', 1} };
// m2 = { {'a', 3}, {'b', 2}, {'c', 1} }
3.成员函数
erase(key) 删除从 key 出发的映射 O(log n) ;unordered->平均 O(1),最坏 O(n)
#include <iostream>
#include <map>
int main() {
std::map<char, int> m;
m['b'] = 1;
m['r'] = 2;
m['o'] = 3;
// m = { {'b', 1}, {'r', 2}, {'o', 3} }
m.erase('o');
// m = { {'b', 1}, {'r', 2} }
for (auto el : m) {
std::cout << el.first << ' ' << el.second << std::endl;
}
return 0;
}
b 1
r 2
(十)string:字符串
1.定义与初始化
std::string s1;
// s1 = ""
std::string s2 = "banana";
// s2 = "banana"
std::string s3(5, 'a');
// s3 = "aaaaa"
2.成员函数
4.特殊:
#include <iostream>
#include <string>
int main() {
std::string str1 = "hello";
std::string str2 = "world";
std::string str3 = str1 + "," + str2;
std::cout << str3 << std::endl;
std::cout << str3.substr(2, 7) << std::endl;//截取的是从索引 2 开始、长度为 7 的子字符串,即 "llo,wor"
return 0;
}
hello,world
llo,wor
#include <iostream>
#include <string>
int main() {
int a = std::stoi("25");//"25" 是要转换的字符串,
//函数将其解析为整数 25,并将结果存储在变量 a 中。
long long b = std::stoll("8");//"8" 是要转换的字符串,
//函数将其解析为整数 8,并将结果存储在变量 b 中
std::string c = std::to_string(a * b);//a * b 进行乘法运算,
//由于 a 是 int 类型,b 是 long long 类型,运算结果会自动转换为 long long 类型,
std::cout << c << std::endl;
return 0;
}
200
(十一)sort:升序排序(支持数组, vector , deque , string 等支持随机访问的容器:O(n log n))
函数签名:
void sort(Iterator first, Iterator last);
void sort(Iterator first, Iterator last, Compare cmp);
(十二)reverse:反转序列(支持数组,vector,deque ,list, string 等支持顺序访问的容器; O(n))
函数签名:
void reverse(Iterator first, Iterator last);
first :头部元素的迭代器(或指针);
(十三)unique:移除序列中连续重复的元素(不会直接删除元素,而是将重复的元素移动到序列
末尾,并返回指向新序列末尾的迭代器;支持数组,vector,deque,list,string 等支持顺序访问的容器;O(n))
函数签名:
Iterator unique(Iterator first, Iterator last);
(十四)lower_bound(在有序(升序)序列中二分查找「第一个大于等于给定值」的元素,并返回它的迭代器;支持数组, vector , deque , string 等支持随机访问的容器; O(log n)。
1.分类:lower_bound,upper_bound (查找「第一个大于给定值」的元素)
2.函数签名:
Iterator lower_bound(Iterator first, Iterator last, T value);
first :头部元素的迭代器(或指针);
#include <iostream>
#include <algorithm>
#include <vector>
27
int main() {
std::vector<int> vec = {1, 2, 4, 4, 5, 6, 7};
auto it = std::lower_bound(vec.begin(), vec.end(), 4);
// 查找第一个 ≥ 4 的元素
std::cout << std::distance(vec.begin(), it);
// 输出它对应的下标
return 0;
}
2
三.C++ 语法糖
(一) auto
auto x = 10;
// 鉴定为 int
auto y = 3.14;
// 鉴定为 double
auto z = 'A'
// 鉴定为 char
std::string s;
auto p = s.begin();
// 鉴定为 std::string::iterator
float solve() {
...
}
int main() {
1auto result = solve();
// 若 solve() 的类型发生变更,此处不必跟着变更
...
}
(二)范围 for 循环(更简单地遍历顺序容器中的每一个元素; 支持数组, vector , deque , list , string 等支持顺序访问的容器)
#include <iostream>
int main() {
2
for (auto el : {1, 1, 4, 5, 1, 4}) {
std::cout << el << ' ';
}
return 0;
}
1 1 4 5 1 4
(三)using别名定义
#include <map>
template <typename T>
using intTo = std::map<int, T>;
int main() {
intTo<int> map1;
intTo<char> map2;
intTo<double> map3;
...
}
(四)Lambda 表达式(允许在任何地方定义函数:Lambda 表达式是一个语句,不能漏掉最后的分号;当采用 [&] 时,Lambda 函数可以修改外部的变量,采用 [=] 时则不行;-> returnType 可省略。)
auto funcName = [&](Type1 x1, Type2 x2, ...) -> returnType {
...
};
#include <iostream>
#include <string>
int main() {
auto toUpperCase = [=](std::string s) -> std::string {
for (auto& ch : s)
ch = toupper(ch);
return s;
};
std::cout << toUpperCase("hello, world");
return 0;
}
HELLO, WORLD

1626

被折叠的 条评论
为什么被折叠?



