学习 C++(1 月 21 日)

一.时空复杂度

(一)语句(基本单位
(二)语句执行次数(反映程序的运行时间

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)

push(value): 在栈顶插入value O(1)
pop() :删除栈顶元素 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)

back() :返回队尾元素 O(1)
empty() :返回是否为空 O(1)
size() :返回元素个数O(1)
push(value): 在队尾插入 value O(1)
pop() :删除队头元素 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:优先队列(会自动排序但其内部元素不可见,只允许访问最大的元素)
top() 返回最大的元素 O(1)
empty() 返回是否为空 O(1)
size() 返回元素个数 O(1)
push(value) 往堆中插入 value O(log n)
pop() 删除最大的元素 O(log n)
#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}
2.成员函数:
assign(count, value) 初始化为 count value O(n)
at(pos) 返回第 pos 个元素 O(1)
operator [pos] 返回第 pos 个元素 O(1)
front() 返回第一个元素 O(1)
back() 返回最后一个元素 O(1)
begin() 返回头部迭代器 O(1)
end() 返回尾部迭代器 O(1);(尾部迭代器均指向尾部元素的后继,而不是尾部元素。)
 
empty() 返回是否为空 O(1)
size() 返回元素个数 O(1)
clear() 清空 O(n)
push_back(value) 在尾部插入 value O(1)
pop_back() 删除尾部元素 O(1)
resize(count) 将容量调整为 count O(n)
#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}
2.成员函数:

assign(count, value) 初始化为 count value O(n)

at(pos) 返回第 pos 个元素 O(1)

operator [pos] 返回第 pos 个元素 O(1)

front()返回第一个元素 O(1)

back() 返回最后一个元素 O(1)
begin() 返回头部迭代器O(1)
end() 返回尾部迭代器 O(1)
empty()返回是否为空 O(1)
size()返回元素个数 O(1)
clear() 清空O(n)
push_back(value) 在尾部插入 value O(1)
pop_back() 删除尾部元素 O(1)
push_front(value) 在头部插入 value O(1)
pop_front() 删除头部元素 O(1)
resize(count) 将容量调整为 count O(n)
#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}
2.成员函数:
assign(count, value) 初始化为 count value O(n)
front() 返回第一个元素 O(1)
back() 返回最后一个元素 O(1)
begin() 返回头部迭代器 O(1)
end() 返回尾部迭代器 O(1)
empty() 返回是否为空 O(1)
size() 返回元素个数 O(1)
clear() 清空O(n)
insert(pos, value) 在迭代器 pos 处插入 value O(1)
erase(pos) 删除迭代器 pos 处的元素 O(1)
push_back(value) 在尾部插入 value O(1)
pop_back() 删除尾部元素 O(1)
push_front(value) 在头部插入 value O(1)
pop_front() 删除头部元素 O(1)
resize(count) 将容量调整为 count O(n)
#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'}
3.成员函数
begin() 返回头部迭代器 O(1);unordered->O(1)
end() 返回尾部迭代器 O(1);unordered->O(1)
empty() 返回是否为空 O(1) ;unordered->(1)
size() 返回元素个数 O(1) ;unordered->O(1)
clear() 清空 O(n);unordered->O(n)
insert(value) 插入一个 value O(log n) unordered;unordered->平均 O(1),最坏 O(n)
erase(value) 删除所有 value O(log n) unordered;unordered->平均 O(1),最坏 O(n)
erase(iter) 删除迭代器 iter 指向的单个元素 O(log n) ;unordered->平均 O(1),最坏 O(n)
count(value) 返回 value 的个数O(log n) ;unordered->平均 O(1),最坏 O(n)
find(value) 返回一个 value 的迭代器O(log n);unordered->平均 O(1),最坏 O(n)
(九)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.成员函数

at(key) 返回 key 映射的元素 O(log n) ;unordered->平均 O(1),最坏 O(n)
operator [key] 返回 key 映射的元素 (如没有则创建) O(log n) ;unordered->平均 O(1),最坏 O(n)
begin() 返回头部迭代器 O(1);unordered->O(1)
end() 返回尾部迭代器 O(1);unordered->O(1)
empty() 返回是否为空 O(1);unordered->O(1)
size() 返回元素个数 O(1);unordered->O(1)
clear() 清空 O(n) ;unordered->O(n)
count(key) 返回 key 映射的元素个数 O(log n) ;unordered->平均 O(1),最坏 O(n)

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.成员函数

assign(count, value) 初始化为 count value O(n)
at(pos) 返回第 pos 个字符 O(1)
operator[pos] 返回第 pos 个字符 O(1)
front() 返回第一个字符 O(1)
back() 返回最后一个字符 O(1)
c_str() 返回 c 风格字符串 O(n)
begin() 返回头部迭代器 O(1)
end() 返回尾部迭代器 O(1)
empty() 返回是否为空 O(1)
size() 返回字符串长度 O(1)
clear() 清空 O(n)
push_back(ch) 在尾部插入 ch 字符 O(1)
pop_back() 删除尾部字符 O(1)
append(str) 在尾部插入 str 字符串 O(n)
operator += str 在尾部插入 str 字符串 O(n)
resize(count) 将字符串长度调整为 count O(n)
substr(pos, count) 截取第 pos 个字符开始、长度为 count 的子串 O(n)
substr(pos) 截取第 pos 个字符开始到末尾的子串 O(n)
3.非成员函数
operator str1 + str2 拼接字符串 O(n)
operator str1 == str2 等于 O(n)
operator str1 < str2 小于(按字典序比较) O(n)
operator str1 > str2 大于(按字典序比较) O(n)
operator str1 <= str2 小于等于(按字典序比较) O(n)
operator str1 >= str2 大于等于(按字典序比较) O(n)
stoi(str) 字符串转 int O(n)
stoll(str) 字符串转 long long O(n)
stoull(str) 字符串转 unsigned long long O(n)
stof(str) 字符串转 float O(n)
stod(str) 字符串转 double O(n)
stold(str) 字符串转 long double O(n)
to_string(value) 数字转字符串(支持 int double 等) O(n)

4.特殊:

cin 可以直接输入 string
cout 可以直接输出 string
scanf 不可以输入 string
printf 可以输出 string 的 c 风格形式,如 printf("%s", str.c_str()); 

#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);
first :头部元素的迭代器(或指针);
last :尾部元素的后继的迭代器(或指针),同end();
cmp (非必须):自定义比较函数,用于控制排序的升降。
(十二)reverse:反转序列(支持数组,vector,deque ,list, string 等支持顺序访问的容器; O(n))

函数签名:

void reverse(Iterator first, Iterator last);

first :头部元素的迭代器(或指针);

last :尾部元素的后继的迭代器(或指针)。
(十三)unique:移除序列中连续重复的元素(不会直接删除元素,而是将重复的元素移动到序列
末尾,并返回指向新序列末尾的迭代器;支持数组,vector,deque,list,string 等支持顺序访问的容器;O(n)

函数签名:

Iterator unique(Iterator first, Iterator last);
first :头部元素的迭代器(或指针);
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 :头部元素的迭代器(或指针);

last :尾部元素的后继的迭代器(或指针);
value :用户的给定值。
#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++ 语法糖

语法糖(Syntactic sugar)指在编程语言中添加的便于使用的语法。它不改变语言功能,但能
提高代码可读性。
(一) auto 
声明变量时用 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值