C++相较于其他语言一个显著的优点为,它封装了一些stl(standared template library,标准模板库)容器,使用起来就不需要自己动手实现了,就可以节省更多时间用于思考代码的思路以及代码主要部分。本篇文章介绍常用的stl容器极其操作。
要使用vector容器,首先要包含头文件
vector<int> a //初始为空
vector<int> a(10) //初始有10个位置
vector<int> a(10, 3) //初始有10个位置,且都被初始化为了3
vector<int> a[10] //声明一个vector数组,每个数组元素都是vector
常用vector操作:
遍历vector有三种常用操作
演示一下,执行以下代码:
#include
#include
using namespace std;
int main()
{
vector<int> a;
for (int i = 1; i <= 10; i ++ ) a.push_back(i);
//用下标
for (int i = 0; i < 10; i ++ ) cout << a[i] << ' ';
cout << endl;
//用迭代器
for (auto i = a.begin(); i != a.end(); i ++ ) cout << *i << ' ';
cout << endl;
//用范围for语句
for (auto x : a) cout << x << ' ';
cout << endl;
return 0;
}
还有必要说一下vector变长的倍增思想。首先要说一下计算机分配内存的时间,每次分配内存和大小关系不大,和分配次数有很大关系。比如一次分配1000个位置,和1000次分配1个位置,后者要慢很多很多。所以vector在变长的时候,要尽量减少分配次数。在gcc环境下,假设当前有n个位置,如果用的位置超过了n个,那就申请2n个位置,并把前n个位置上的元素复制到新分配的前n个里。平均下来,vector插入一个数的时间复杂度是O(1)的。且这样分配次数为logn,有效减少申请次数。用程序展示一下:
#include
#include
using namespace std;
int main()
{
vector<int> a;
while (1)
{
int x;
cin >> x;
a.push_back(x);
cout << "当前元素数量" << a.size() << endl;
cout << "当前分配空间" << a.capacity() << endl;
}
}
C++对字符串进行了封装,让字符串的操作更加简单。要使用string类,要包含
常用string操作:
substr()的用法:substr接受两个参数,substr(a, b),a表示截取子串的其实下标,b表示截取长度。如果越界,则截取到最后停止。此外,substr还可以只接受一个参数a,那么就从下标a开始截取到最后。
一些额外的操作:string还可以使用+=操作。
举例:
#include
#include
using namespace std;
int main()
{
string a = "abcdef";
string b = a;
string c = a.substr(1, 3);
cout << c << endl;
cout << a.substr(2) << endl;
cout << endl;
b += "1234";
cout << b << endl;
b += '*';
cout << b << endl;
return 0;
}
使用queue容器,要包含
常用queue操作:
注意,queue没有clear操作。但是也可以用重新构造的方法清空队列:
#include
#include
using namespace std;
int main()
{
queue<int> q;
q.push(1), q.push(2);
cout << q.front() << endl;
//重新构造来清空队列
q = queue<int>();
if (q.empty()) cout << "队列为空" << endl;
return 0;
}
优先队列其实就是一个堆。要使用priority_queue,需要包含头文件
常用priority_queue操作:
默认情况下,priority_queue构造的是一个大根堆。但是有一个固定的语法构造小根堆,要包含
#include
#include
#include
using namespace std;
int main()
{
//默认大根堆
priority_queue<int> q1;
for (int i = 1; i <= 10; i ++ ) q1.push(i);
//构造小根堆
priority_queue<int, vector<int>, greater<int>> q2;
for (int i = 1; i <= 10; i ++ ) q2.push(i);
cout << q1.top() << endl << q2.top() << endl;
return 0;
}
要改变存储的数据类型,只要改变3个int即可。注意,priority_queue也没有clear操作。
使用stack容器,要包含头文件
常用stack操作:
注意,stack没有clear操作。另外,栈的所有操作都是O(1)的。
要使用deque容器,要包含头文件
常用deque操作:
同时,deque支持随机寻址操作,即取下标。
要使用set和multiset容器,要包含头文件
常用set和multiset操作:
要使用map和multimap容器,要包含头文件
常用map和multimap操作:
map和multimap还支持一个很强的操作:像使用数组一样使用map。意思是:a[类型一元素] = 类型二元素。
举个例子:
#include
#include
#include
using namespace std;
int main()
{
map<string, int> a;
a["abc"] = 1;
a["bcd"] = 2;
a["cde"] = 3;
cout << (*a.upper_bound("a")).second << endl;
cout << (*a.upper_bound("b")).second << endl;
return 0;
}
这一坨容器是基于哈希表实现的。要使用unordered_set和unordered_multiset容器,要包含头文件
使用的话,要包含头文件
最常用的用处就是,当我们需要一个10000 * 10000的bool矩阵时,如果存成bool类型,那就是108个字节(C++中bool类型占一个字节),直接爆内存了。但是如果使用压位存储,那就只需要108位了,减少了内存消耗,并且能满足需求。
#include
#include
using namespace std;
int main()
{
//声明时,括号内是位数
bool a[1000][1000];
bitset<1000> b[1000];
cout << sizeof a << endl << sizeof b << endl;
return 0;
}
常用bitset操作:
此外,bitset还支持~(非)、&(与)、|(或)、^(异或)、>>(右移位)和<<(左移位)操作。