C++ 标准模板库的核心包括以下三个组件:
组件 描述
容器(Containers) 容器是用来管理某一类对象的集合。C++ 提供了各种不同类型的容器,比如 deque、list、vector、map 等。
算法(Algorithms) 算法作用于容器。它们提供了执行各种操作的方式,包括对容器内容执行初始化、排序、搜索和转换等操作。
迭代器(iterators) 迭代器用于遍历对象集合的元素。这些集合可能是容器,也可能是容器的子集。
这三个组件都带有丰富的预定义函数,帮助我们通过简单的方式处理复杂的任务。
本文简要介绍:
- vector
- set
- list
- queue
- map
不定长数组:vector
vector是一个模板类,所以需要用vector<int>a或者vector<double>b来声明一个vector。vector<int>是一个类似于int a[]的整数数组,而vector<string>就是一个类似于string a[]的字符串数组。
**相比于数组的优势:**可以直接赋值,还可以作为函数的参数或者返回值,而无需像传递数组那样另外用一个变量指定元素个数。
vector的使用:
要想用vector首先得包含头文件vector
#include <vector>
常用操作:
#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template <typename T> //定义一个模板
void showvector(vector<T> v)// 使用迭代器 iterator 访问值
{
for (vector<T>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it;
}
cout << endl;
}
int main(int argc, char const *argv[])
{
vector<int>a;//初始化vector
for(int i = 0; i < 5; i++){ //插入5个顺序元素
a.push_back(i);//向尾部插入
}
cout<<a.size()<<endl;//输出vector长度
for(int i = 0; i < a.size(); i++){// 访问向量中的 5 个值
cout << "value of vec [" << i << "] = " << a[i] << endl;
}
cout<<a.size()<<endl;//输出vector的长度
a.resize(4);//修改长度
cout<<a[4] <<endl;//虽然长度变了,但是之前存入的值还是能被访问到
a.pop_back(); //删除最后一个元素
a.insert(a.begin()+1,9); //在第二个位置插入新元素
a.insert(a.begin() + 1, 8,8); //连续插入8个8
a.erase(a.begin() + 3); //删除第四个元素
a.erase(a.begin(),a.begin()+3); //连续删除3个元素
for(int i = 0; i < a.size(); i++){// 访问向量中的 5 个值
cout << "value of vec [" << i << "] = " << a[i] << endl;
}
a.clear(); //清除所有内容
}
集合set
set就是数学上的集合—每个元素最多只出现一次。set里面的元素是有序的且唯一的,只要你往set里添加元素,它就会自动排序,而且,如果你添加的元素set里面本来就存在,那么这次添加操作就不执行。和sort一样,自定义类型也可以构造set,但同样必须定义“小于”运算符
-
不能直接改变元素值,因为那样会打乱原本正确的顺序,要改变元素值必须先删除旧元素,则插入新元素
-
不提供直接存取元素的任何操作函数,只能通过迭代器进行间接存取,而且从迭代器角度来看,元素值是常数
-
元素比较动作只能用于型别相同的容器(即元素和排序准则必须相同)
#include <iostream>
#include <set>
#include <string>
#include <vector>
using namespace std;
void showset(set<string> &v)
{
for (set<string>::iterator it = v.begin(); it != v.end(); it++)
cout << *it<<endl;
}
int main()
{
set<string> s;
s.insert("sfsf");//往set里面添加元素
s.insert("abb");
s.insert("cds");
s.erase(s.begin());//删除,注意不同于vector,只能一个个删除
s.erase("sfsf");//或者删除指定元素
showset(s);
return 0;
}
链表list
list是一个双向链表,而单链表对应的容器则是foward_list。
list即双向链表的优点是插入和删除元素都比较快捷,缺点是不能随机访问元素
值得注意的是,list容器不能调用algorithm下的sort函数进行排序,因为sort函数要求容器必须可以随机存储,而list做不到。所以,list自己做了一个自己用的排序函数。
list<int> l1{ 8,5,7,6,1,2,3,4,5,5,6,7,7 };
l1.sort();
声明一个int型的list:list a;
1、list的构造函数
lista{1,2,3}
lista(n) //声明一个n个元素的列表,每个元素都是0
lista(n, m) //声明一个n个元素的列表,每个元素都是m
lista(first, last) //声明一个列表,其元素的初始值来源于由区间所指定的序列中的元素,first和last是迭代器
2、begin()和end()
通过调用list容器的成员函数begin()得到一个指向容器起始位置的iterator,可以调用list容器的end()函数来得到list末端下一位置
3、push_back()和push_front()
使用list的成员函数push_back和push_front插入一个元素到list中。其中push_back()是从list的末端插入,而push_front()是从list的头部插入。
4、empty()
判断list是否为空
5、resize()
调用resize(n)将list的长度改为只容纳n个元素,超出的元素将被删除。如果n比list原来的长度长,那么默认超出的部分元素置为0。也可以用resize(n, m)的方式将超出的部分赋值为m。
例子:
listb{1, 2, 3, 4};
b.resize(2);
list中输出元素:1,2
listb{1, 2, 3, 4};
b.resize(6);
list中输出元素:1,2,3,4,0,0
listb{1, 2, 3, 4};
b.resize(6,9);
list中输出元素:1,2,3,4,9,9
6、clear()
清空list中的所有元素
7、front()和back()
通过front()可以获得list容器中的头部元素,通过back()可以获得list容器的最后一个元素。注意:当list元素为空时,这时候调用front()和back()不会报错。因此在编写程序时,最好先调用empty()函数判断list是否为空,再调用front()和back()函数。
8、pop_back()和pop_front()
使用pop_back()可以删掉尾部第一个元素,pop_front()可以删掉头部第一个元素。注意:list必须不为空,如果当list为空的时候调用pop_back()和pop_front()会使程序崩掉。
9、assign()
有两种使用情况:
(1)a.assign(n, val):将a中的所有元素替换成n个val元素
例如:
listb{1,2,3,4,5};
b.assign(5,10);
b中的元素变为10, 10, 10, 10, 10
(2)a.assign(b.begin(), b.end())
lista{6,7,8,9};
listb{1,2,3,4,5};
b.assign(a.begin(),a.end());
b中的元素变为6,7,8,9
10、swap()
交换两个链表。a.swap(b)和swap(a, b),都可以完成a链表和b链表的交换。
例子:
lista{6,7,8,9};
listb{1,2,3,4,5};
swap(a, b); //或a.swap(b)
a中元素变为1,2,3,4,5
b中元素变为6,7,8,9
11、reverse()
可以实现list的逆置
例子:
listb{1,2,3,4,5};
reverse(b.begin(),b.end());
b中元素变为5,4,3,2,1
12、merge()
a.merge(b) 调用结束后b变为空,a中元素包含原来a和b的元素。
例子:
lista{6,7,8,9};
listb{2, 1, 3, 6, 5};
a.merge(b,greater());
a中元素变为:6,7,8,9,2,1,3,6,5
lista{6,7,8,9};
listb{2, 1, 3, 6, 5};
a.merge(b);
a中元素变为:2,1,3,6,5,6,7,8,9
13、insert()
在指定位置插入一个或多个元素
a.insert(a.begin(),100); //在a的开始位置(即头部)插入100
a.insert(a.begin(),2, 100); //在a的开始位置插入2个100
a.insert(a.begin(),b.begin(), b.end());//在a的开始位置插入b从开始到结束的所有位置的元素
14、erase()
删除一个元素或一个区域的元素
a.erase(a.begin()); //将a的第一个元素删除
a.erase(a.begin(),a.end()); //将a的从begin()到end()之间的元素删除。
15、remove()函数
从list中删除元素
lista{6,7,8,9,7,10};
a.remove(7);
删除了a中所有值为7的元素,此时a中元素为6,8,9,10
queue
queue 模板类的定义在头文件中。
与stack 模板类很相似,queue 模板类也需要两个模板参数,一个是元素类型,一个容器类
型,元素类型是必要的,容器类型是可选的,默认为deque 类型。
定义queue 对象的示例代码如下:
queue q1;
queue q2;
queue 的基本操作有:
入队,如例:q.push(x); 将x 接到队列的末端。
出队,如例:q.pop(); 弹出队列的第一个元素,注意,并不会返回被弹出元素的值。
访问队首元素,如例:q.front(),即最早被压入队列的元素。
访问队尾元素,如例:q.back(),即最后被压入队列的元素。
判断队列空,如例:q.empty(),当队列空时,返回true。
访问队列中的元素个数,如例:q.size()
#include <cstdlib>
#include <iostream>
#include <queue>
using namespace std;
int main()
{
int e,n,m;
queue<int> q1;
for(int i=0;i<10;i++)
q1.push(i); //向队尾插入元素
if(!q1.empty()) cout<<"queue is not empty";//判断是否为空
n=q1.size();//返回队列内元素的数目
cout<<n<<endl;
m=q1.back();//访问队尾元素
cout<<m<<endl;
for(int j=0;j<n;j++)
{
e=q1.front();//访问队首元素
cout<<e<<" ";
q1.pop();//弹出队首元素
}
return 0;
}
map
map运用了哈希表地址映射的思想,也就是key-value的思想,来实现的。
声明
例:
map<string,int>;//声明一个key为string,value为int的map
常用函数
clear
清除 map 中所有元素;
erase
删除 map 中指定位置的元素;
insert
在 map 指定位置添加 pair 类型的元素;
find
获取 map 中元素的迭代器;
begin, end
map 的正向迭代器的起始位置与终点位置;
rbegin, rend
// 1. 直接定义
map<char,int> mymap;
mymap['a'] = 10;
// 2. 复制
map<char, int> second(mymap);
//修改值
second['a']=1002;
//使用insert函数插入
mymap.insert(pair<char,int>('f',100) );
本文主要参考:
- 《算法竞赛入门经典(第二版)》
- C++ STL快速入门