C++常用STL总结

由于刷算法题常常可以用到STL中的类和函数,所以做一个总结。

容器类通用

迭代器:
都有 begin(),end() 函数来返回指向第一个、最后一个元素的下一个(这个要注意)的迭代器
使用时,迭代器的类型统一用 auto 即可,方便操作
不同容器的迭代器不一样,有的支持随机访问,有的不能随机访问,但是能双向访问

insert() && erase():
大多数容器类都能通过迭代器进行插入,删除。不过不同容器类的时间复杂度不一样。

输出格式

头文件:
#include<iomanip>

设置精度:
setprecision()
设置宽度:
setw()
设置对齐方式:
left,right,internal
设置输出格式:
fixed,scientific
设置填充:
setfill()
设置基数:
dec,hex,oct

标准输入

cin:
cin >> a 返回的是cin自身的引用(cin是istream类的对象)
不过在条件表达式中,返回值会被隐式地转化为布尔值,如果输入成功,则为true,否则为false

getline:
定义在<string>中。
istream& getline(std::istream& input, std::string& str, char delim = '\n')
第一个参数是一个流对象,第二个参数是输入到的字符串,第三个参数是分割符。
返回也是流对象的引用,与 cin 的返回值类似

流对象

读写文件:
#include<fstream>
ifstream是只读的流,ofstream是只写的流,fstream是可读可写的流

// 打开文件(读文件类似)
// 要注意,在默认模式下写文件是会清空文件的,所以要指定app的模式写
    ifstream inputFile("data.txt");
    if (!inputFile.is_open()) {
        cerr << "无法打开文件 data.txt" << endl;
        return 1;
    }

// 从文件第二个字符之后开始写
// 打开文件,同时指定读写模式
    fstream file("example.txt", ios::in | ios::out);

    if (!file.is_open()) {
        cerr << "无法打开文件 example.txt" << endl;
        return 1;
    }

    // 定位到第二个字符之后(索引为 2 的位置)
    file.seekp(2);

    // 写入内容
    file << "XY";

    	

文件写入模式

命令行操作

编译:g++ -o 输出文件名 输入文件名
运行:./output

传参:首先要定义好main函数
int main(int argc, char* argv[]) {
    // 打印程序名
    cout << "程序名: " << argv[0] << endl;

    // 遍历所有参数
    for (int i = 1; i < argc; ++i) {
        cout << "参数 " << i << ": " << argv[i] << endl;
    }

    return 0;
}
其中argc是参数的个数,argv是参数数组,argv[0]为程序的名称,从argv[1]开始才是程序真正的参数

最大最小值

#include<climits>;

INT_MIN 表示int类型的最小值。
INT_MAX 表示int类型的最大值。

从而避免对最大最小值进行硬编码

常用计算函数

头文件:
#include<algorithm>
min(),max()函数定义在这个头文件

#include<cmath>
pow(),sqrt()函数定义在这个头文件

1. sort()函数

头文件:
#include<algorithm>

特性:
仅支持随机访问迭代器的类,如list,map,set等底层使用链表、红黑树的容器是不能直接使用的。

底层的原理叫做Introsort,其思想为:
首先使用快速排序:利用快速排序的高效性对数据进行排序。
监控递归深度:如果快速排序的递归深度超过了某个阈值(通常是 2×logn),则切换到堆排序,以避免快速排序在最坏情况下的性能退化。
处理小数组:对于小规模的子数组(通常小于某个阈值,如1632),使用插入排序进行优化,因为插入排序在小数据量时效率更高

用法:
sort(a.begin(),a.end());	//a是一个容器类,不指定第三个参数 默认升序排序<
sort(a.begin(),a.end(),greater<int>());		//greater<int>()指定使用 >的降序排序

class people{
    public:
    string name;
    int age;
    people(string name,int age){
        this->name = name;
        this->age = age;
    }
};

static bool cmp(const people& p1,const people& p2){		// people对象数组根据age来升序排序
    return p1.age < p2.age;
}

static bool compare(const vector<int>& v1,const vector<int>& v2){	// vector<vector<int>>根据每个vector第一个元素升序排序
    return v1[0] < v2[0];
}

int main(){
    vector<vector<int>>v;
    vector<int>v1 = {1,2,3};
    vector<int>v2 = {2,2,3};
    v.push_back(v2);
    v.push_back(v1);
    sort(v.begin(),v.end(),compare);
    for(int i = 0;i < v.size();i++){
        cout << v[i][0] << " " << v[i][1] << " " << v[i][2] << endl;
    }
}

reverse()函数

头文件:
#include<algorithm>

原理:
实现逻辑是通过两个迭代器分别指向范围的起始位置和结束位置(不包括结束位置),然后逐步交换这两个位置的元素,直到两个迭代器相遇,时间复杂度是O(n)

用法:
reverse(a.begin(),a.end())//a是一个容器类,反转其中所有元素的顺序
reverse(first,last);	// 准确来说是反转first到last-1这个范围内的元素

2. vector类

头文件:
#include<vector>

原理:vector类底层是一片连续的内存空间,这就意味着在中间插入和删除都要移动大量的元素,时间复杂度为O(n)

初始化:
vector<int> a(10);	//包含十个元素的动态数组

修改:
a.push_back(1);		//末尾添加一个
a.pop_back();		//末尾删除一个
a.empty()			//是否为空

访问:
a[1];			// 直接通过下标
a.at(1)// 通过函数进行安全访问
a.front();		// 访问第一个元素
a.back():		// 访问最后一个元素
a.size():		// 获取长度

3. string类

头文件:
#include<string>

输入:
cin >> s;	 //从键盘读取不带空格的字符串
getline(cin,s);		//从键盘读取带空格的字符串(getline函数暂时不深究)
s = s1+s2;		//可以直接拼接
s += s1;

访问
s[1];		// 使用下标访问
s.at(1);	// 安全访问
s.size();	// 获取长度
s.find("hello");	// 查找子串
s.substr(7,5);		// 获取从第7个字符开始,后面5个字符的子串
s.back();	// 访问最后一个字符

修改:
s.replace(7,5,"hello");		//从第7个字符开始,将后面5个字符替换为hello
s.clear();			// 清空字符串
s.pop_back();	// 弹出最后一个字符
s.push_back();	// 在末尾加一个字符

在C++11后,引入了to_string()函数,可以将值转化为string.
在C++11后,引入了stoi()函数,可以将string转化为int类型.(也有stof,stol)

4. set类

set类主要分为两种:底层为红黑树,与底层为哈希表的,对应其底层数据结构的特性

集合底层实现是否有序查询效率增删效率元素是否可重复
set红黑树有序O(logn)O(logn)
multiset红黑树有序O(logn)O(logn)
unordered_set哈希表无序O(1)O(1)
set:
头文件:
#include<set>

插入删除:
set<int>s;
s.insert(10);		// 由于元素不重复,所以每个元素在set中是唯一的,可能插入失败
s.erase(10);		// 删除元素10

查找:
auto it = s.find(10);	// 查找成功则返回对应的迭代器,查找失败则返回s.end()
s.size();		// 查找长度
s.empty();		// 是否为空

遍历:
for(const auto& u : s){...}		// 这个&是有说法的(不用拷贝一份新的对象,减少内存开销),而且const也是有说法的,因为容器内部使用红黑树或者哈希表,如果修改了元素值就会影响到底层的数据结构,所以是不允许修改的,一定要加const
mutiset:
头文件:
#include<set>

操作与set基本一致,但是count()函数的作用就不可以忽略了
unordered_set:
头文件:
#include<unordered_set>

操作与set一致

5.map类

map类与set类类似,也是主要分为两种:底层为红黑树,与底层为哈希表的,对应其底层数据结构的特性

集合底层实现key是否有序查询效率增删效率key是否可重复
map红黑树有序O(logn)O(logn)
multimap红黑树有序O(logn)O(logn)
unordered_map哈希表无序O(1)O(1)
map:
头文件:
#include<map>

插入删除:
map<int,string> m;
m.insert<make_pair(1,"one")>;		// 通过insert插入
m[1] = "one";			// 通过下标插入,若键 1 不存在则插入,若存在则覆盖
m.erase(1);			// 删除键为1的键值对

查找:
auto it = m.find(1);		// 与set中的find函数是一样的,查找成功返回迭代器,查找失败返回m.end()
string v = m[1];		// 通过下标访问键为1的键值对,获取值,若键不存在,就插入默认值,这里是{1,""}
string v = m.at(1)		// 安全访问,键不存在则抛出异常

multimap和unordered_map也是差不多的

6.stack类

头文件:
#include<stack>

原理:stack是一个容器适应类,由底层的deque,vector或者list来实现

初始化:
stack<int>s;
stack<int,vector<int>>s;	//因为栈默认的底层实现是双端队列deque,但是也可以用数组或者链表来实现

增删改查:
s.push();	// 入栈一个元素
s.pop();	// 出栈一个元素,不返回任何值
s.top();	// 返回栈顶元素
s.size();	// 栈中元素个数
s.empty();	// 是否为空

7.queue类

头文件:
#include<queue>

原理:queue是一个容器适应类,由底层的deque或者list来实现

初始化:
queue<int>q;
queue<int,list<int>>q;	// 底层默认使用deque,也可以使用list

增删改查:
q.front();	// 获取队头元素的引用
q.back();	// 获取队尾元素的引用
q.push();	// 队尾入队
q.pop();	// 队头出队
q.emplace();	// 在队尾直接构造一个元素
q.size();	// 元素个数
q.empty();	// 是否为空

8.deque类

头文件:
#include<deque>

原理:内部是一个双向队列。使用分段的连续内存块。它将数据存储在多个固定大小的内存块中,这些内存块通过指针连接。这种设计使得deque在两端操作时效率很高,但在中间插入或删除元素的效率较低

增删改查:
deque<int>deq;
deq.push_back();	// 尾部插入
deq.push_front();	// 头部插入
deq.pop_back();		// 尾部删除
deq.pop_front();	// 头部删除
deq.front();	// 获取队头元素
deq.back();		// 获取队尾元素

9.list类

头文件:
#include<list>

原理:内部是一个双向链表

增删改查:
list<int>l;
l.push_back();	// 尾部插入
l.push_front();	 // 头部插入
l.inset();		// 通过迭代器插入元素
l.erase();		// 通过迭代器删除元素

10.priority_queue类

头文件:
#include<queue>

priority_queue<int,vector<int>,greater<int>>pq;		// 三个参数都要指明,这是建立一个小根堆
priority_queue<int,vector<int>>pq;	// 不指定第三个参数,默认是大根堆

class people{
    public:
    string name;
    int age;
    people(string name,int age){
        this->name = name;
        this->age = age;
    }
};

class MyCmp{	// 对于自定义对象people建立小根堆
    public:
    bool operator()(const people& p1,const people& p2){
        return p1.age > p2.age;
    }
};

int main(){
    priority_queue<people,vector<people>,MyCmp>pq;
    pq.push(people("lear1",12));
    pq.push(people("lear2",15));
    pq.push(people("lear3",10));
    cout << pq.top().name << endl;
}

还有一种构造方式,使用Lambda表达式:
vector<int>counts(26,0);

auto cmp = [&](const char& c1,const char& c2){
            return counts[c1-'a'] < counts[c2-'a'];
        };
        
priority_queue<char,vector<char>,decltype(cmp)> que{cmp};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值