C++ STL(标准模板库)是一套功能强大的 C++ 模板类,提供了通用的模板类和函数,这些模板类和函数可以实现多种流行和常用的算法和数据结构,如向量
、链表
、队列
、栈
。
C++ 标准模板库的核心包括以下三个组件:
STL 的基本观念就是将数据和操作分离。数据由容器进行管理,操作则由算法进行,而迭代器在两者之间充当粘合剂,使任何算法都可以和任何容器交互运作。
为了应付程序中的不同需求,STL 准备了两类共七种基本容器类型:
对于容器,主要的操作有:容器的建立、插入元素、删除元素、查询、遍历、计算元素个数、检查元素是否为空、输出容器包含的内容。
一种序列式容器,事实上和数组差不多,但它比数组更优越。一般来说数组不能动态拓展,因此在程序运行的时候不是浪费内存,就是造成越界。而 vector 正好弥补了这个缺陷,当内存空间不够时,需要重新申请一块足够大的内存并进行内存的拷贝。
总结:相当于可拓展的数组(动态数组),随机访问快,在头部和中间插入或删除效率低,但在尾部插入或删除效率高,适用于对象简单,变化较小,并且频繁随机访问的场景。
vector()
:无参数 - 构造一个空的vectorvector(size_type num)
:数量(num) - 构造一个大小为num,值为Type默认值的Vectorvector(size_type num, const TYPE &val)
:数量(num)和值(val) - 构造一个初始放入num个值为val的元素的Vectorvector(const vector &from)
:vector(from) - 构造一个与vector from 相同的vectorvector(input_iterator start, input_iterator end)
:迭代器(start)和迭代器(end) - 构造一个初始值为[start,end)区间元素的Vector(注:半开区间).vector(initializer_list<value_type> il, const allocator_type& alloc = allocator_type())
C++11新提供的方法,类似如下方式:std::vector<int>a{1, 2, 3, 4, 5}
std::vector<int>a = {1, 2, 3, 4, 5}
v1 == v2
v1 != v2
v1 <= v2
v1 >= v2
v1 < v2
v1 > v2
v[]
assign()
:对Vector中的元素赋值at()
: 返回指定位置的元素back()
: 返回最末一个元素begin()
: 返回第一个元素的迭代器capacity()
: 返回vector所能容纳的元素数量(在不重新分配内存的情况下)clear()
: 清空所有元素empty()
: 判断Vector是否为空(返回true时为空)end()
: 返回最末元素的迭代器(译注:实指向最末元素的下一个位置)erase()
: 删除指定元素front()
: 返回第一个元素get_allocator()
: 返回vector的内存分配器insert()
: 插入元素到Vector中max_size()
: 返回Vector所能容纳元素的最大数量(上限)pop_back()
: 移除最后一个元素push_back()
: 在Vector最后添加一个元素rbegin()
: 返回Vector尾部的逆迭代器rend()
: 返回Vector起始的逆迭代器reserve()
: 设置Vector最小的元素容纳数量resize()
: 改变Vector元素数量的大小size()
: 返回Vector元素数量的大小swap()
: 交换两个Vector#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> vecTemp;
for (int i = 0; i < 6; i++) {
vecTemp.push_back(i);
}
for (int i = 0; i < vecTemp.size(); i++) {
cout << vecTemp[i] << " "; // 输出:0 1 2 3 4 5
}
std::cout << '\n';
return 0;
}
Output
0 1 2 3 4 5
deque是Double-Ended Queues(双向队列)的缩写,是双向开口的连续内存空间(动态将多个连续空间通过指针数组接合在一起),随时可以增加一段新的空间。deque 的最大任务就是在这些分段的连续空间上,维护其整体连续的假象,并提供随机存取的接口。
总结:支持随机访问,但效率没有 vector 高,在头部和尾部插入或删除效率高,但在中间插入或删除效率低,适用于既要频繁随机访问,又要关心两端数据的插入与删除的场景。
deque<T> queT
:queue采用模板类实现,queue对象的默认构造形式deque<T> queT(size)
:构造大小为size的deque,其中值为T类型的默认值deque<T> queT(size, val)
:构造大小为size的deque,其中值为valdeque(const deque &que)
:拷贝构造函数deque(input_iterator start, input_iterator end)
:迭代器构造函数back()
:返回最后一个元素front()
:返回第一个元素insert()
pop_back()
: 删除尾部的元素pop_front()
: 删除头部的元素push_back()
:在尾部加入一个元素push_front()
: 在头部加入一个元素at()
:访问指定位置元素operator[] (size_type n)
:重载[]操作符empty()
:判断队列是否为空size()
:返回队列的大小#include <iostream>
#include <deque>
using namespace std;
int main() {
std::deque<int> first; /// 默认构造形式
std::deque<int> second(5, 200); /// 构造大小为5的deque,其中值为200
std::deque<int> third(second.begin(), second.end()); /// 迭代器构造函数
std::deque<int> fourth(third); /// 拷贝构造函数
/// 迭代器构造函数可用于复制数组
int myInts[] = {19, 20, 21, 22};
std::deque<int> fifth(myInts, myInts + sizeof(myInts) / sizeof(int));
std::cout << "The contents of fifth are:";
for (std::deque<int>::iterator it = fifth.begin(); it != fifth.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
Output
The contents of fifth are: 19 20 21 22
List 由双向链表(doubly linked list)实现而成,元素存放在堆中,每个元素都是放在一块内存中。没有空间预留习惯,所以每分配一个元素都会从内存中分配,每删除一个元素都会释放它占用的内存。
总结:不支持随机访问,在任意位置的插入和删除效率都较高,适用于经常进行插入和删除操作并且不经常随机访问的场景。
list (const allocator_type& alloc = allocator_type())
list (size_type n, const value_type& val = value_type(), const allocator_type& alloc = allocator_type())
template <class InputIterator> list (InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type())
list (const list& x)
assign()
:给list赋值back()
:返回最后一个元素begin()
:返回指向第一个元素的迭代器clear()
:删除所有元素empty()
:如果list是空的则返回trueend()
:返回末尾的迭代器erase()
:删除一个元素front()
:返回第一个元素get_allocator()
:返回list的配置器insert()
:插入一个元素到list中max_size()
:返回list能容纳的最大元素数量merge()
:合并两个listpop_back()
:删除最后一个元素pop_front()
:删除第一个元素push_back()
:在list的末尾添加一个元素push_front()
:在list的头部添加一个元素rbegin()
:返回指向第一个元素的逆向迭代器remove()
:从list删除元素remove_if()
:按指定条件删除元素rend()
:指向list末尾的逆向迭代器resize()
:改变list的大小reverse()
:把list的元素倒转size()
:返回list中的元素个数sort()
:给list排序splice()
:合并两个listswap()
:交换两个listunique()
:删除list中重复的元素#include <iostream>
#include <list>
using namespace std;
int main() {
list<char> listTemp;
for (char c = 'a'; c <= 'z'; ++c)
listTemp.push_back(c);
while (!listTemp.empty()) {
cout << listTemp.front() << " ";
listTemp.pop_front();
}
return 0;
}
Output
a b c d e f g h i j k l m n o p q r s t u v w x y z
set(集合)顾名思义,就是数学上的集合,集合中以一种特定的顺序保存唯一的元素。
总结:由红黑树实现,其内部元素依据其值自动排序,每个元素值只能出现一次,不允许重复,且插入和删除效率比用其他序列容器高,适用于经常查找一个元素是否在某集合中且需要排序的场景。
set()
:无参数 - 构造一个空的setset(InputIterator first, InputIterator last)
:迭代器的方式构造setset(const set &from)
:copyd的方式构造一个与set from 相同的setset(input_iterator start, input_iterator end)
:迭代器(start)和迭代器(end) - 构造一个初始值为[start,end)区间元素的Vector(注:半开区间).set (initializer_list<value_type> il, const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type())
C++11新提供的方法,类似如下方式:std::set<int>a{1, 2, 3, 4, 5};
begin()
:返回指向第一个元素的迭代器clear()
:清除所有元素count()
:返回某个值元素的个数empty()
:如果集合为空,返回trueend()
:返回指向最后一个元素的迭代器equal_range()
:返回集合中与给定值相等的上下限的两个迭代器erase()
:删除集合中的元素find()
:返回一个指向被查找到元素的迭代器get_allocator()
:返回集合的分配器insert()
:在集合中插入元素lower_bound()
:返回指向大于(或等于)某值的第一个元素的迭代器key_comp()
:返回一个用于元素间值比较的函数max_size()
:返回集合能容纳的元素的最大限值rbegin()
:返回指向集合中最后一个元素的反向迭代器rend()
:返回指向集合中第一个元素的反向迭代器size()
:集合中元素的数目swap()
:交换两个集合变量upper_bound()
:返回大于某个值元素的迭代器value_comp()
:返回一个用于比较元素间的值的函数#include <iostream>
#include <set>
using namespace std;
int main() {
set<int> setTemp;
setTemp.insert(3);
setTemp.insert(1);
setTemp.insert(2);
setTemp.insert(1);
for (int it : setTemp) {
cout << it << " ";
}
return 0;
}
Output
1 2 3
当 set 集合中的元素为结构体时,该结构体必须实现运算符 <
的重载:
#include <set>
#include <string>
using namespace std;
struct People {
string name;
int age;
bool operator<(const People p) const {
return age < p.age;
}
};
int main(int argc, char *argv[]) {
set<People> setTemp;
setTemp.insert({"天理", 19});
setTemp.insert({"天工", 20});
setTemp.insert({"天大", 21});
setTemp.insert({"南开", 18});
set<People>::iterator it;
for (it = setTemp.begin(); it != setTemp.end(); it++) {
printf("学校:%s 就读年龄:%d\n", (*it).name.c_str(), (*it).age);
}
return 0;
}
Output
学校:南开 就读年龄:18
学校:天理 就读年龄:19
学校:天工 就读年龄:20
学校:天大 就读年龄:21
可以看到结果是按照年龄由小到大的顺序排列。另外 string 要使用c_str()
转换一下,否则打印出的是乱码。
Multiset 和 set 相同,只不过它允许重复元素,也就是说 multiset 可包括多个数值相同的元素。这里不再做过多介绍。
map 由红黑树实现,其元素都是 “键值/实值” 所形成的一个对组(key/value pairs),map 内部自建一颗红黑树,这颗树具有对数据自动排序的功能,所以在 map 内部所有的数据都是有序的。
总结:元素为键值对,key 和 value 可以是任意你需要的类型,每个元素都有一个键,且只能出现一次,不允许重复,根据 key 快速查找记录,适用于需要存储一个数据字典,并要求方便地根据key找value的场景。
map (const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type())
template <class InputIterator> map (InputIterator first, InputIterator last,const key_compare& comp = key_compare(),const allocator_type& = allocator_type())
map (const map& x)
map (const map& x, const allocator_type& alloc)
map (map&& x)
map (map&& x, const allocator_type& alloc)
map (initializer_list<value_type> il, const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type())
begin()
:返回指向map头部的迭代器clear()
:删除所有元素count()
:返回指定元素出现的次数empty()
:如果map为空则返回trueend()
:返回指向map末尾的迭代器equal_range()
:返回特殊条目的迭代器对erase()
:删除一个元素find()
:查找一个元素get_allocator()
:返回map的配置器insert()
:插入元素–key_comp()
:返回比较元素key的函数lower_bound()
:返回键值>=给定元素的第一个位置max_size()
:返回可以容纳的最大元素个数rbegin()
:返回一个指向map尾部的逆向迭代器rend()
:返回一个指向map头部的逆向迭代器size()
:返回map中元素的个数swap()
:交换两个mapupper_bound()
:返回键值>给定元素的第一个位置value_comp()
:返回比较元素value的函数#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<int, string> mapTemp;
mapTemp.insert({1, "后端码匠"});
mapTemp.insert({2, "音视频开发"});
mapTemp.insert({3, "后端开发"});
mapTemp.insert({4, "前端开发"});
mapTemp.insert({4, "客户端开发"});
map<int, string>::iterator it;
for (it = mapTemp.begin(); it != mapTemp.end(); it++) {
printf("编号:%d 岗位:%s\n", (*it).first, (*it).second.c_str());
}
return 0;
}
Output
编号:1 岗位:后端码匠
编号:2 岗位:音视频开发
编号:3 岗位:后端开发
编号:4 岗位:前端开发
multimap 和 map 相同,但允许重复元素,也就是说 multimap 可包含多个键值(key)相同的元素。这里不再做过多介绍。
除了以上七个基本容器类别,为满足特殊需求,STL还提供了一些特别的(并且预先定义好的)容器配接器,根据基本容器类别实现而成。包括:
stack(堆栈)实现了一个先进后出(FILO)的数据结构。
stack<T> stkT
:采用模板类实现,stack对象的默认构造形式stack(const stack &stk)
:拷贝构造函数size()
:返回栈中的元素数top()
:返回栈顶的元素pop()
:从栈中取出并删除元素push(x)
:向栈中添加元素xempty()
:在栈为空时返回truequeue 容器对元素采取 FIFO(先进先出)的管理策略。也就是说,它是个普通的缓冲区(buffer)。
explicit queue (const container_type& ctnr)
explicit queue (container_type&& ctnr = container_type())
template <class Alloc> explicit queue (const Alloc& alloc)
template <class Alloc> queue (const container_type& ctnr, const Alloc& alloc)
template <class Alloc> queue (container_type&& ctnr, const Alloc& alloc)
template <class Alloc> queue (const queue& x, const Alloc& alloc)
template <class Alloc> queue (queue&& x, const Alloc& alloc)
back()
:返回最后一个元素empty()
:如果队列空则返回真front()
:返回第一个元素pop()
:删除第一个元素push()
:在末尾加入一个元素size()
:返回队列中元素的个数优先队列类似队列, 但是在这个数据结构中的元素按照一定的规则排列有序。在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高优先级先出 (first in, largest out)的行为特征。首先要包含头文件#include, 他和queue不同的就在于我们可以自定义其中数据的优先级, 让优先级高的排在队列前面,优先出队。优先队列具有队列的所有特性,包括队列的基本操作,只是在这基础上添加了内部的一个排序,它本质是一个堆实现的。
priority_queue<Type, Container, Functional>
:
empty()
, size()
, front()
, push_back()
,pop_back()
。比如vector,deque等等,但不能用list。STL里面默认用的是vector)。可选top()
:访问队头元素empty()
:队列是否为空size()
:返回队列内元素个数push()
:插入元素到队尾 (并排序)emplace()
:原地构造一个元素并插入队列pop()
:弹出队头元素swap()
:交换内容