一、序列式容器
1. vector
2. deque
deque容器是双端队列,支持快速随机访问,在头尾位置插入/删除元素速度很快。
- vector容器对于在头部的插入、删除效率低,且数据量越大,效率越低。相对而言,deque容器对于在头部的插入、删除速度比vector容器快
- vector容器访问元素的速度比deque容器快
- deque容器的内存重分配优于vector容器,因为其内部结构不需要复制所有元素
deque容器内部有一个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据。中控器维护的是每个缓冲区的地址,使得使用deque容器时像是一片连续的内存空间。
3. list
STL中的list容器是一个双向循环链表,只支持双向顺序访问,在list容器中任何位置插入/删除速度很快。
- 链表中的迭代器只支持前移和后移
- 插入/删除操作不会造成原有的迭代器失效
所有不支持随机访问迭代器的容器, 不可以用标准算法, 但内部会提供对应一些算法!
#include <iostream>
#include <list>
using namespace std;
void printList(const list<int>& L)
{
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int main()
{
list<int> L;
L.push_back(90);
L.push_back(30);
L.push_back(20);
L.push_back(70);
printList(L); // 90 30 20 70
// 反转
L.reverse();
printList(L); // 70 20 30 90
// 排序,默认升序
L.sort();
printList(L); // 20 30 70 90
// 排序,降序排序
L.sort([](const int& num1, const int& num2) {return num1 > num2; });
printList(L); // 90 70 30 20
system("pause");
return 0;
}
什么情况下用vector,什么情况下用list,什么情况下用deque?
- vector支持快速随机访问,但在非尾部插入/删除数据时效率很低,适合对象简单,对象数量变化不大,随机访问频繁的情况
- 需要从首尾两端进行插入/删除操作的时候可以选择deque
- 除非必要,我们尽可能选择使用vector而非deque,因为deque的迭代器比vector迭代器复杂很多
- list不支持随机访问,适用于对象大,对象数量变化频繁,插入和删除频繁的情况。
二、配接器
1. stack
栈是一种先进后出的数据结构,栈中只有顶端的元素才可以被外界使用,因此栈不允许有遍历行为。
#include <iostream>
#include <stack>
using namespace std;
int main()
{
stack<int> s;
// 入栈
s.push(10);
s.push(20);
s.push(30);
// 栈是否为空
while (!s.empty())
{
// 返回栈顶元素
cout << "栈顶元素为: " << s.top() << endl;
// 出栈
s.pop();
}
// 返回栈的大小
cout << "栈的大小为:" << s.size() << endl;
system("pause");
return 0;
}
2. queue
队列是一种先进先出的数据结构,队列允许从一端新增元素,从另一端移除元素,队列中只有队头和队尾才可以被外界使用,因此队列不允许有遍历行为。
#include <iostream>
#include <queue>
#include <string>
using namespace std;
class Person
{
friend ostream& operator<<(ostream& out, const Person& p);
public:
Person(string name, int age) {
this->m_Name = name;
this->m_Age = age;
}
private:
string m_Name;
int m_Age;
};
ostream& operator<<(ostream& out, const Person& p)
{
out << "姓名:" << p.m_Name << " 年龄:" << p.m_Age;
return out;
}
int main()
{
queue<Person> q;
Person p1("唐僧", 30);
Person p2("孙悟空", 1000);
Person p3("猪八戒", 900);
Person p4("沙僧", 800);
// 入队
q.push(p1);
q.push(p2);
q.push(p3);
q.push(p4);
// 队列是否为空
while (!q.empty())
{
// 返回队头元素
cout << q.front() << endl;
// 返回队尾元素
cout << q.back() << endl;
// 出队
q.pop();
}
// 返回队列大小
cout << "队列大小为: " << q.size() << endl;
system("pause");
return 0;
}
三、关联式容器
1. set / multiset
- set/multiset属于关联式容器,底层结构是用红黑树实现
- 所有元素在插入时自动按升序排序
- set不允许容器中有重复的元素,multiset允许容器中有重复的元素
- 对于自定义数据类型,set容器必须指定排序规则
// 基本使用
#include <iostream>
#include <set>
using namespace std;
void printSet(set<int>& s)
{
for (set<int>::iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
set<int> s;
// 插入
s.insert(10);
s.insert(30);
s.insert(20);
s.insert(40);
s.insert(50);
s.insert(60);
// 容器是否为空
if (s.empty()) {
cout << "set为空" << endl;
}
else {
// 返回容器中元素的数目
cout << "set的大小为: " << s.size() << endl; // 6
}
// 删除
s.erase(s.begin());
printSet(s); // 20 30 40 50 60
s.erase(60);
printSet(s); // 20 30 40 50
// 查找
set<int>::iterator pos = s.find(30);
// 统计
// 对于set容器来说,结果为0或1
int num = s.count(30);
cout << "num = " << num << endl; // 1
system("pause");
return 0;
}
// set不允许容器中有重复的元素,multiset允许容器中有重复的元素
#include <iostream>
#include <set>
using namespace std;
int main()
{
// set不允许插入重复值
// set插入数据的同时会返回插入结果
set<int> s;
pair<set<int>::iterator, bool> ret = s.insert(10);
if (ret.second) {
cout << "第一次插入成功!" << endl; // √
}
else {
cout << "第一次插入失败!" << endl;
}
ret = s.insert(10);
if (ret.second) {
cout << "第二次插入成功!" << endl;
}
else {
cout << "第二次插入失败!" << endl; // √
}
// multiset允许插入重复的值
multiset<int> ms;
ms.insert(10);
ms.insert(10);
for (multiset<int>::iterator it = ms.begin(); it != ms.end(); it++) {
cout << *it << " "; // 10 10
}
cout << endl;
system("pause");
return 0;
}
// 所有元素在插入时自动按升序排序
#include <iostream>
#include <set>
using namespace std;
class MyCompare
{
public:
bool operator()(int v1, int v2) const {
return v1 > v2;
}
};
int main()
{
set<int> s1;
s1.insert(10);
s1.insert(40);
s1.insert(20);
s1.insert(30);
s1.insert(50);
// set容器默认升序排序
for (auto v : s1)
cout << v << " ";
cout << endl; // 10 20 30 40 50
// 指定降序排序
set<int, MyCompare> s2;
s2.insert(10);
s2.insert(40);
s2.insert(20);
s2.insert(30);
s2.insert(50);
for (auto v : s1)
cout << v << " ";
cout << endl;
system("pause");
return 0;
}
// 对于自定义数据类型,set容器必须指定排序规则
#include <iostream>
#include <set>
using namespace std;
class Person
{
friend ostream& operator<<(ostream& out, const Person& p);
friend class ComparePerson;
public:
Person(string name, int age) {
this->m_Name = name;
this->m_Age = age;
}
private:
string m_Name;
int m_Age;
};
ostream& operator<<(ostream& out, const Person& p) {
out << "姓名: " << p.m_Name << " 年龄: " << p.m_Age;
return out;
}
class ComparePerson
{
public:
// 按照年龄降序排序
bool operator()(const Person& p1, const Person& p2) const {
return p1.m_Age > p2.m_Age;
}
};
int main()
{
// 对于自定义数据类型,必须指定排序规则
set<Person, ComparePerson> s;
Person p1("刘备", 30);
Person p2("关羽", 27);
Person p3("张飞", 24);
Person p4("赵云", 21);
s.insert(p1);
s.insert(p2);
s.insert(p3);
s.insert(p4);
for (auto p : s)
cout << p << endl;
system("pause");
return 0;
}
2. map / multimap
- map / multimap属于关联式容器,底层结构是用红黑树实现
- map中所有元素都是pair,第一个元素为键值,起到索引作用,第二个元素为实际值
- 所有元素都会根据元素的键值自动按升序排序
- map不允许容器中有重复键值元素,multimap允许容器中有重复键值元素
- 对于自定义数据类型,map容器必须指定排序规则
// 基本使用
#include <iostream>
#include <map>
using namespace std;
int main()
{
map<int, int> m;
// 插入
m.insert(pair<int, int>(1, 10));
m.insert(make_pair(2, 20));
m.insert(map<int, int>::value_type(3, 30));
// 不建议使用[]插入
m[4] = 40;
// 如果没有这个键,就创建这个键值对,值为0
m[5];
for (const auto& p : m)
cout << p.first << " " << p.second << " "; // 1 10 2 20 3 30 4 40 5 0
// 可以用于访问
cout << m[1] << endl; // 10
// 删除
m.erase(m.begin()); // 2 20 3 30 4 40 5 0
m.erase(5); // 2 20 3 30 4 40
// 容器是否为空
if (m.empty()) {
cout << "map为空" << endl;
}
else {
// 返回容器中元素的数目
cout << "map的大小为: " << m.size() << endl;
}
// 按键查找
map<int, int>::iterator pos = m.find(3);
// 按键统计
// 对于map,结果为0或者1
int num = m.count(3);
cout << "num = " << num << endl; // 1
system("pause");
return 0;
}
// 更改排序方式
#include <iostream>
#include <map>
using namespace std;
class MyCompare {
public:
bool operator()(int v1, int v2) const {
return v1 > v2;
}
};
int main()
{
map<int, int, MyCompare> m;
m.insert(make_pair(1, 10));
m.insert(make_pair(2, 20));
m.insert(make_pair(3, 30));
m.insert(make_pair(4, 40));
m.insert(make_pair(5, 50));
for (map<int, int, MyCompare>::iterator it = m.begin(); it != m.end(); it++) {
cout << "key = " << it->first << " value = " << it->second << endl;
}
system("pause");
return 0;
}
参考:https://www.bilibili.com/video/BV1et411b73Z