C++stl库(中文标准模板库)学习
vector 、 stack 、 queue 、 map 、 set 这些在C++中都叫做容器,既然都是容器,那么他们就会有相通的地方和各自的特点。
vector(向量/动态数组)
vector 是数组容器,即动态数组,它能够在运⾏阶段设置数组的长度、在末尾增加新的数据、在中间插⼊新的值、长度任意可被改变。
使用的时候要引入头文件 #include <vector>
vector 可以⼀开始不定义大小,之后用 resize 方法分配大小,也可以⼀开始就定义大小,之后还可以对它插⼊删除动态改变它的大小~而且不管在 main 函数里还是在全局中定义,它都能够直接将所有的值初始化为0(不用显式地写出来,默认就是所有的元素为0)
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v(5);//定义v同时分配5的长度,且值默认为0
vector<int> v0(3,6);//定义v0同时分配3的长度,每个元素为6
vector<int> v1;//定义动态数组v1,但没有分配
v1.resize(8);//通过resize函数分配大小
arr[5]={0,2,1,6,3};
vector<int> &arr;//当然,用指针传入也是可以的
}
v.end()取的是最后一个元素的后面一个位置。(该位置内没有函数)
常用函数 | 功能 | 常用函数 | 功能 |
---|---|---|---|
push_back | 在数组的最后添加一个数据 | size | 当前使用数据的大小 |
pop_back | 去掉数组的最后一个数据 | resize | 改变当前使用数据的大小,如果它比当前使用的大,者填充默认值 |
at | 得到编号位置的数据 | reserve | 改变当前vecotr所分配空间的大小 |
begin | 得到数组头的指针 | erase | 删除指针指向的数据项 |
end | 得到数组的最后一个单元+1的指针 | clear | 清空当前的vector |
front | 得到数组头的引用 | rbegin | 将vector反转后的开始指针返回(其实就是原来的end-1) |
back | 得到数组的最后一个单元的引用 | rend | 将vector反转构的结束指针返回(其实就是原来的begin-1) |
max_size | 得到vector最大可以是多大 | empty | 判断vector是否为空 |
capacity | 当前vector分配的大小 | swap | 与另一个vector交换数据 |
set(集合)
set是集合容器,元素唯一且有序。大部分基本操作与从vector类似,但set不支持随机访问,需要用迭代器访问。set在存入一个元素时,会调整其顺序,放到合适的位置。在加入元素时,一般只用insert函数。
使用时需要引入头文件#include <set>
#include <iostream>
#include <set>
using namespace std;
int main() {
set<int> s; // 定义⼀个空集合s
s.insert(1); // 向集合s⾥⾯插⼊⼀个1
cout << *(s.begin()) << endl; // 输出集合s的第⼀个元素 (前⾯的星号表示要对指针取值)
for (int i = 0; i < 6; i++) {
s.insert(i); // 向集合s⾥⾯插⼊i
}
for (auto it = s.begin(); it != s.end(); it++) { // ⽤迭代器遍历集合s⾥⾯的每⼀个元素
cout << *it << " ";
}
cout << endl << (s.find(2) != s.end()) << endl; // 查找集合s中的值,如果结果等于s.end()表示未找到 (因为s.end()表示s的最后⼀个元素的下⼀个元素所在的位置)
cout << (s.find(10) != s.end()) << endl; // s.find(10) != s.end()表示能找到10这个元素
s.erase(1); // 删除集合s中的1这个元素
cout << (s.find(1) != s.end()) << endl; // 这时候元素1就应该找不到了
return 0;
}
常用函数 | 功能 | 常用函数 | 功能 |
---|---|---|---|
begin() | 返回指向第一个元素的迭代器 | insert() | 在集合中插入元素 |
clear() | 清除所有元素 | lower_bound() | 返回指向大于(或等于)某值的第一个元素的迭代器 |
count() | 返回某个值元素的个数 | key_comp() | 返回一个用于元素间值比较的函数 |
empty() | 如果集合为空,返回true | max_size() | 返回集合能容纳的元素的最大限值 |
end() | 返回指向最后一个元素的迭代器 | rbegin() | 返回指向集合中最后一个元素的反向迭代器 |
equal_range() | 返回集合中与给定值相等的上下限的两个迭代器 | rend() | 返回指向集合中第一个元素的反向迭代器 |
erase() | 删除集合中的元素 | size() | 集合中元素的数目 |
find() | 返回一个指向被查找到元素的迭代器 | swap() | 交换两个集合变量 |
get_allocator() | 返回集合的分配器 | upper_bound() | 返回大于某个值元素的迭代器 |
map(键值对容器)
map是键值对(key-value),可以将任何基本类型映射到任何基本类型,会自动将所有的键值对按照键从小到大排序。
使用时需要引入头文件#include <map>
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, int> m; // 定义⼀个空的map集合 m,键是string类型的,值是int类型的
m["hello"] = 2; // 将key为"hello", value为2的键值对(key-value)存⼊map中
cout << m["hello"] << endl; // 访问map中key为"hello"的value, 如果key不存在,则返回0
cout << m["world"] << endl;
m["world"] = 3; // 将"world"键对应的值修改为3
m[","] = 1; // 设⽴⼀组键值对,键为"," 值为1
// ⽤迭代器遍历,输出map中所有的元素,键⽤it->first获取,值⽤it->second获取
for (auto it = m.begin(); it != m.end(); it++) {
cout << it->first << " " << it->second << endl;
}
// 访问map的第⼀个元素,输出它的键和值
cout << m.begin()->first << " " << m.begin()->second << endl;
// 访问map的最后⼀个元素,输出它的键和值
cout << m.rbegin()->first << " " << m.rbegin()->second << endl;
// 输出map的元素个数
cout << m.size() << endl;
return 0;
}
map的函数大致和前两个容器set,vector相类似,这里就不再列出。但insert函数的用法有一点不同,在这里提一下
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, int> m;
m.insert(map<string,int>::value_type("D",666));//创建键值对插入
m.insert({666,'D'});//创建临时键值对插入
pair<string,int>p("D",999);
m.insert(p);//先创建一个键值对再插入
}
pair(对值)
pair可以将两个数据配成一对,作为一组数据。当需要配对,或者返回两个元素时可以用(如在map中创造键对值)。可以把pair看作是一个结构体。
pair<class T1,class T2>pairname(value1,value2)
make_pair(v1, v2);
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
typedef pair<string,string> Author;//使用typedef来定义多个相同的pair类型(例子是<string,string>类型的)
Author sf("hlb","czj");
Author kz("fwj","cxy");
return 0;
}
queue(队列)
queue是一种数据结构,适用FIFO技术(先进先出),顾名思义,就像排队一样。先插入的元素就在前面,排队时,是排在后面,删除(处理)是从前面开始的。
在使用时需要引入头文件#include <queue>
#include <iostream>
#include <queue>
using namespace std;
int main() {
queue<int> q; // 定义⼀个空队列q
for (int i = 0; i < 6; i++) {
q.push(i); // 将i的值依次压⼊队列q中
}
cout << q.front() << " " << q.back() << endl; // 访问队列的队⾸元素和队尾元素
cout << q.size() << endl; // 输出队列的元素个数
q.pop(); // 移除队列的队⾸元素
return 0;
}
函数 | 描述 |
---|---|
empty | 测试队列是否为空。如果队列为空,则该函数返回true,否则返回false。 |
size | 返回队列中元素的个数。 |
front | 返回第一个元素。元素起着非常重要的作用,因为所有的删除操作都是在front元素上执行的。 |
back | 返回最后一个元素。该元素起着非常重要的作用,因为所有插入操作都在后面元素上执行。 |
push | 用于在末尾插入一个新元素。 |
pop | 用于删除第一个元素。 |
emplace | 用于在当前后元素上方的队列中插入新元素。 |
swap | 用于交换参考中两个容器的内容。 |
relational operators | 非成员函数指定队列所需的关系运算符。 |
uses allocator | 非成员函数将分配器用于队列。 |
priority-queue(优先队列)
priority-queue相较于普通队列,可以在队列中赋予元素优先级,删除和调用时,最高优先级优先。
priority_queue<数据类型, 容器类型(默认为vector),比较优先的方式>;
//升序队列
priority_queue <int,vector<int>,greater<int> > q;
//降序队列
priority_queue <int,vector<int>,less<int> >q;
stack(栈)
stack也是一种数据结构,适用LIFO技术(后进先出)。像一摞书一样,先插入的元素在尾部(叠放在最下层),所有插入和删除操作都是在堆栈的顶部元素本身进行的(拿书只能从顶部拿)。
使用时需要引入头文件#include <stack>
#include <iostream>
#include <stack>
using namespace std;
int main() {
stack<int> s; // 定义⼀个空栈s
for (int i = 0; i < 6; i++) {
s.push(i); // 将元素i压⼊栈s中
}
cout << s.top() << endl; // 访问s的栈顶元素
cout << s.size() << endl; // 输出s的元素个数
s.pop(); // 移除栈顶元素
return 0;
}
函数 | 描述 |
---|---|
constructor | 构造堆栈容器。 |
empty | 测试堆栈是否为空。如果堆栈为空,则该函数返回true,否则返回false。 |
size | 返回堆栈容器的大小,该大小是堆栈中存储的元素数量的度量。 |
top | 访问堆栈的顶部元素。该元素起着非常重要的作用,因为所有插入和删除操作都是在顶部元素上执行的。 |
push | 在堆栈顶部插入新元素。 |
pop | 将堆栈中的元素从顶部删除。 |
emplace | 在当前顶部元素上方的堆栈中插入新元素。 |
swap | 交换引用的两个容器的内容。 |
relational operators | 非成员函数指定堆栈所需的关系运算符。 |
uses allocator | 非成员函数将分配器用于堆栈。 |
string
string s = "hello world"; // 赋值字符串
string s2 = s;
string s3 = s + s2; // 字符串拼接直接⽤+号就可以
string s4;
cin >> s4; // 读⼊字符串
cout << s<<endl; // 输出字符串
getline(cin, s); // 读取⼀⾏的字符串,包括空格
cout << s.length()<<endl; // 输出字符串s的⻓度
string s5 = s.substr(4); // 表示从下标4开始⼀直到结束
string s6 = s.substr(5, 3); // 表示从下标5开始,3个字符
iterator(迭代器)
-
正向迭代器:容器类名::iterator 迭代器名;
-
常量正向迭代器:容器类名::const_iterator 迭代器名;
-
反向迭代器:容器类名::reverse_iterator 迭代器名;
-
常量反向迭代器:容器类名::const_reverse_iterator迭代器名;
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v;
for (int n = 0; n<5; ++n)
v.push_back(n); //push_back成员函数在vector容器尾部添加一个元素
vector<int>::iterator i; //定义正向迭代器
for (i = v.begin(); i != v.end(); ++i) { //用迭代器遍历容器
cout << *i << " "; //*i 就是迭代器i指向的元素
*i *= 2; //每个元素变为原来的2倍,告诉迭代可以参与计算
}
cout << endl;
//用反向迭代器遍历容器
for (vector<int>::reverse_iterator j = v.rbegin(); j != v.rend(); ++j)
cout << *j << " ";
return 0;
}
-
正向迭代器。假设 p 是一个正向迭代器,则 p 支持以下操作:++p,p++,*p。此外,两个正向迭代器可以互相赋值,还可以用
==
和!=
运算符进行比较。 -
双向迭代器。双向迭代器具有正向迭代器的全部功能。除此之外,若 p 是一个双向迭代器,则
--p
和p--
都是有定义的。--p
使得 p 朝和++p
相反的方向移动。 -
随机访问迭代器。随机访问迭代器具有双向迭代器的全部功能。若 p 是一个随机访问迭代器,i 是一个整型变量或常量,则 p 还支持以下操作:
- p+=i:使得 p 往后移动 i 个元素。
- p-=i:使得 p 往前移动 i 个元素。
- p+i:返回 p 后面第 i 个元素的迭代器。
- p-i:返回 p 前面第 i 个元素的迭代器。
- p[i]:返回 p 后面第 i 个元素的引用。
此外,两个随机访问迭代器 p1、p2 还可以用 <、>、<=、>= 运算符进行比较。p1<p2
的含义是:p1 经过若干次(至少一次)++
操作后,就会等于 p2。其他比较方式的含义与此类似。
对于两个随机访问迭代器 p1、p2,表达式p2-p1
也是有定义的,其返回值是 p2 所指向元素和 p1 所指向元素的序号之差(也可以说是 p2 和 p1 之间的元素个数减一)。
容器 | 迭代器功能 |
---|---|
vector | 随机访问 |
deque | 随机访问 |
list | 双向 |
set / multiset | 双向 |
map / multimap | 双向 |
stack | 不支持迭代器 |
queue | 不支持迭代器 |
priority_queue | 不支持迭代器 |