跳到主要内容
C++常用容器详解:Stack、Queue、List、Set、Map | 极客日志
C++ 算法
C++常用容器详解:Stack、Queue、List、Set、Map 综述由AI生成 C++ STL 中常用的五种容器:栈(stack)、队列(queue)、链表(list)、集合(set/multiset)和映射(map/multimap)。内容涵盖各容器的概念、底层结构、常用接口函数及代码示例。重点对比了不同容器的特性,如栈的后进先出、队列的先进先出、链表的动态存储优势、集合的自动排序及唯一性、映射的键值对关联等。通过实际案例展示了容器的构造、赋值、插入、删除、查找及排序操作,适用于 C++ 初学者掌握标准模板库基础数据结构。
鲜活 发布于 2026/3/24 更新于 2026/5/5 19K 浏览一、Stack 容器
概念:栈,一种先进后出 (First In, Last Out)的数据结构,只有一个出口(栈顶),另外一端为栈底。入栈使用 push,出栈使用 pop。
栈不允许有遍历的行为 ,只有栈顶元素才能被外界所访问到。
栈可以判断容器是否为空,有函数 empty();
可以访问栈内元素个数,函数 size();
1. Stack 常用的接口
构造函数:
stack<T>stk;
stack (const stack &stk);
赋值操作:
stack& operator =(const stack &stk);
数据存取:
push (elem);
pop ();
top ();
大小操作:
empty ();
size ();
示例:
void test01 () {
stack<int >stk;
stk.push (1 );
stk.push (2 );
stk.push (3 );
cout << "栈的原始大小:" << stk.size () << endl;
while (!stk.empty ()) {
cout << stk. () << endl;
stk. ();
}
cout << << stk. () << endl;
}
top
pop
"栈的大小:"
size
二、Queue 容器 概念:队列,一种先进先出 (First In, First Out)的数据结构,有两个出口(两个端口)。对头出队,对尾入队。
两端都可以访问数据
只有队头和队尾才可以被访问到;不接受遍历行为
插入数据,入队 push,在队尾进行操作
删除数据,出队 pop,在队头进行操作
1. 常用的接口 queue<T> q;
queue (const queue &que);
q.empty ();
q.size ();
q.push (elem);
q.pop ();
q.back ();
q.front ();
class Person {
public :
Person (int age, string name) {
m_age = age;
m_name = name;
}
int m_age;
string m_name;
};
void test02 () {
queue<Person>q;
Person p1 (1 ,"lan" ) ;
Person p2 (2 ,"xi" ) ;
Person p3 (3 ,"fei" ) ;
Person p4 (4 ,"mei" ) ;
Person p5 (5 ,"nuan" ) ;
q.push (p1);
q.push (p2);
q.push (p3);
q.push (p4);
q.push (p5);
cout << "对内元素:" << q.size () << endl;
while (!q.empty ()) {
cout << "队头元素:" << q.front ().m_age << " " << q.front ().m_name << endl;
cout << "队尾元素:" << q.back ().m_age << " " << q.back ().m_name << endl;
q.pop ();
}
cout << "队内大小:" << q.size () << endl;
}
三、List 容器
1. 概念 链表 ,一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的。
链表由一系列结点组成;结点由两个部分组成(一个是存储数据元素的数据域,另一个是存储下一个节点地址的指针域 )
优点:可以对任意的位置进行快速的添加或删除元素,只需要添加/删除对应结点,修改指针即可
缺点:对于容器的遍历速度,没有数组快(数组是连续的存储空间,只需要偏移地址就可,但链表要先去寻找下一个元素的地址,再访问);占用的存储空间比数组大(存储数据域和指针域)
STL 中的链表是一个双向循环链表 ,即两端都可以进行遍历访问,每个结点有两个指针,一个指向左边(上一个结点)的元素,一个指向右边(下一个结点)的元素
链表不能跳跃式访问 ,因为不是连续的存储空间,所以只能一个一个找,是双向迭代器。
链表执行删除和插入方便,修改指针即可,不需要移动大量元素,vector 需要移动元素
空间和时间耗费比较大,插入和删除操作都不会造成原有的 list 迭代器失效,不影响,还是指向原有。vector 会失效(因为 vector 若内存空间大小改变,就会重新寻找新的空间存储数据,所以原来的迭代器会失效,因为那一片内存空间已经不是最新的数据存储空间了)。
2. List 构造函数 list<T>lst;
list (beg,end);
list (n,elem);
list (const list &lst);
void printList (const list<int >& L) {
for (list<int >::const_iterator it = L.begin (); it != L.end (); it++) {
cout << *it << " " ;
}
cout << endl;
}
void test03 () {
list<int >l1;
l1. push_back (1 );
l1. push_back (2 );
l1. push_back (3 );
l1. push_back (4 );
l1. push_back (5 );
printList (l1);
list<int >l2 (l1. begin (), l1. end ());
printList (l2);
list<int >l3 (l2);
printList (l3);
list<int >l4 (7 , 8 );
printList (l4);
}
3. List 赋值和交换 assign (beg,end);
assign (n,elem);
list& operator =(const list &lst);
swap (lst);
void test04 () {
list<int >l1;
l1. push_back (1 );
l1. push_back (2 );
l1. push_back (3 );
l1. push_back (4 );
l1. push_back (5 );
l1. push_back (6 );
printList (l1);
list<int >l2;
l2 = l1;
printList (l2);
list<int >l3;
l3. assign (l2. begin (), l2. end ());
printList (l3);
list<int >l4;
l4. assign (7 , 8 );
printList (l4);
l2. swap (l4);
printList (l2);
printList (l4);
}
4. List 容器大小操作 size ();
empty ();
resize (num);
resize (num,elem);
void test05 () {
list<int >l1;
l1. push_back (1 );
l1. push_back (2 );
l1. push_back (3 );
l1. push_back (4 );
l1. push_back (5 );
printList (l1);
if (l1. empty ()) {
cout << "l1 is empty!" << endl;
} else {
cout << "l1 is not empty!" << endl;
cout << "容器大小:" << l1. size () << endl;
}
l1. resize (6 );
printList (l1);
l1. resize (7 , 7 );
printList (l1);
}
5. List 容器的插入和删除 push_back (elem);
pop_back ();
push_front (elem);
pop_front ();
insert (pos,elem);
insert (pos,n,elem);
insert (pos,beg,end);
clear ();
erase (beg,end);
erase (pos);
remove (elem);
void test06 () {
list<int >l1;
l1. push_back (2 );
l1. push_back (3 );
l1. push_front (1 );
l1. push_front (0 );
printList (l1);
l1. pop_back ();
l1. pop_front ();
printList (l1);
l1. insert (l1. begin (), 0 );
printList (l1);
list<int >::iterator it = l1. begin ();
l1. insert (++it, 0 );
printList (l1);
it = l1. begin ();
l1. erase (it);
printList (l1);
it = l1. begin ();
l1. erase (++it);
printList (l1);
l1. remove (0 );
printList (l1);
l1. clear ();
printList (l1);
}
6. List 容器的数据粗存取 void test07 () {
list<int >l;
l.push_back (1 );
l.push_back (2 );
l.push_back (3 );
l.push_back (4 );
l.push_back (5 );
cout << "the first elem is: " << l.front () << endl;
cout << "the last elem is: " << l.back () << endl;
}
由于 list 容器的底层结构的原因,每个数据不是用连续的线性空间存储,每个结点的地址不连续,所以不支持 [] 和 at() 随机访问。迭代器只能一个一个的 ++,–,不支持跳跃式的随机访问
7. List 容器的反转和排序 bool myCompare (int v1,int v2) {
return v1 > v2;
}
void test08 () {
list < int >l;
l.push_back (1 );
l.push_back (2 );
l.push_back (6 );
l.push_back (5 );
l.push_back (3 );
l.push_back (4 );
l.sort ();
printList (l);
l.reverse ();
printList (l);
}
所有不支持随机访问的迭代器都不可以用标准的算法 algorithm,比如 sort(支持随机访问的迭代器就可以使用 sort(beg,end))。不提供随机访问的迭代器,内部会提供一些算法函数,比如这里的 sort
排序案例 将 Person 自定义数据类型进行排序,Person 中属性有姓名、年龄、身高。按照年龄进行升序排序,如果年龄相同按照身高进行降序排序
class Person {
public :
Person (int age, string name, int high) {
this ->m_Age = age;
this ->m_Name = name;
this ->m_High = high;
}
int m_Age;
string m_Name;
int m_High;
};
bool comparePerson (Person& p1, Person& p2) {
if (p1. m_Age == p2. m_Age) {
return p1. m_High > p2. m_High;
}
return p1. m_Age < p2. m_Age;
}
void test01 () {
Person p1 (10 , "懒羊羊" , 10 ) ;
Person p2 (13 , "喜羊羊" , 15 ) ;
Person p3 (13 , "沸羊羊" , 16 ) ;
Person p4 (12 , "美羊羊" , 13 ) ;
Person p5 (15 , "暖羊羊" , 18 ) ;
list<Person>l1;
l1. push_back (p1);
l1. push_back (p2);
l1. push_back (p3);
l1. push_back (p4);
l1. push_back (p5);
for (list<Person>::iterator it = l1. begin (); it != l1. end (); it++) {
cout << (*it).m_Name << " " << (*it).m_Age << " " << it->m_High << endl;
}
cout << "排序后:" << endl;
l1. sort (comparePerson);
for (list<Person>::iterator it = l1. begin (); it != l1. end (); it++) {
cout << (*it).m_Name << " " << (*it).m_Age << " " << it->m_High << endl;
}
}
list 类型为自定义类型时,排序需要自定义排序方法
四、Set / Multiset 容器
1. 基本概念 集合容器/关联式容器,所有元素都会在插入时自动被排序 ,底层结构是用二叉树实现。包含头文件 set
set 不允许有重复的元素;
multiset 可以有重复元素;
set<T>st;
set (const set &st);
set& operator =(const set &st);
void test01 () {
set<int >s;
s.insert (1 );
s.insert (5 );
s.insert (3 );
s.insert (4 );
s.insert (2 );
printSet (s);
set<int >s2 (s);
printSet (s2);
set<int >s3;
s3 = s2;
printSet (s3);
}
若要插入重复的值,则使用 multiset。插入数据的方式只有 insert
2. 大小和交换 size ();
empty ();
swap (st);
void test02 () {
set<int >s1;
s1. insert (1 );
s1. insert (2 );
s1. insert (4 );
s1. insert (3 );
s1. insert (5 );
set<int >s2;
s2. insert (6 );
s2. insert (7 );
s2. insert (9 );
s2. insert (5 );
s2. insert (8 );
printSet (s1);
printSet (s2);
if (s1. empty ()) {
cout << "s1 is empty!" << endl;
} else {
cout << "s1 is not empty!" << endl;
cout << "s1 的大小:" << s1. size () << endl;
}
s1. swap (s2);
printSet (s1);
printSet (s2);
}
set 容器不允许有相同的元素存在,所以没有重新设置容器容量大小的函数,只有获得该容器容量大小的函数。
3. Set 容器的插入和删除 insert (elem);
clear ();
erase (pos);
erase (beg,end);
erase (elem);
void test03 () {
set<int >s1;
s1. insert (5 );
s1. insert (7 );
s1. insert (6 );
s1. insert (8 );
s1. insert (4 );
s1. insert (3 );
printSet (s1);
set<int >::iterator it = s1. begin ();
s1. erase (it);
printSet (s1);
s1. erase (4 );
printSet (s1);
s1. clear ();
printSet (s1);
}
4. Set 查找和统计 void test04 () {
set<int >s1;
s1. insert (7 );
s1. insert (8 );
s1. insert (6 );
s1. insert (5 );
s1. insert (9 );
printSet (s1);
set<int >::iterator it;
it = s1.f ind(6 );
if (it != s1. end ()) {
cout << "find it: " << *it << endl;
} else {
cout << "not find" << endl;
}
int num = s1. count (5 );
cout << "num = " << num << endl;
}
对于 set 而言,统计的结果只能是 0 或 1。
5. Set 和 Multiset 的区别
set 不可以插入重复数据,而 multiset 可以;
set 插入数据的同时会返回插入结果,表示插入是否成功;
multiset 不会检测数据,因此可以插入重复数据
void test05 () {
set<int >s1;
pair<set<int >::iterator,bool > ret = s1. insert (7 );
pair<set<int >::iterator,bool > ret1 = s1. insert (7 );
if (ret.second) {
cout << "the first insert is successful!" << endl;
} else {
cout << "the first insert is fail" << endl;
}
if (ret1. second) {
cout << "the second insert is successful" << endl;
} else {
cout << "the second insert is fail" << endl;
}
multiset<int >s2;
s2. insert (7 );
s2. insert (7 );
for (multiset<int >::iterator it = s2. begin (); it != s2. end (); it++) {
cout << *it << " " ;
}
cout << endl;
}
set 容器 insert 插入时,返回值类型为 pair,pair 是一个对组(迭代器,bool)
multiset 容器 insert 插入时,返回值类型是 iterator,直接插入,返回迭代器,所以可以插入重复的值
6. Pair 的使用,创建 Pair 对组 pair<type,type> p (value1,value2) ;
pair<type,type> p = make_pair (value1,value2);
void test06 () {
pair<string, int >p ("懒羊羊" , 10 );
cout << "姓名:" << p.first << " age: " << p.second << endl;
pair<string, int > p1 = make_pair ("喜羊羊" , 13 );
cout << "name: " << p1.f irst << " age: " << p1. second << endl;
}
7. Set 容器排序 class MyCompare {
public :
bool operator () (int v1,int v2) const
{
return v1 > v2;
};
};
void test07 () {
set<int >s1;
s1. insert (7 );
s1. insert (8 );
s1. insert (6 );
s1. insert (5 );
s1. insert (9 );
for (set<int >::iterator it = s1. begin (); it != s1. end (); it++) {
cout << *it << " " ;
}
cout << endl;
set<int , MyCompare>s2;;
s2. insert (9 );
s2. insert (5 );
s2. insert (6 );
s2. insert (7 );
s2. insert (8 );
for (set<int ,MyCompare>::iterator it1 = s2. begin (); it1 != s2. end (); it1++) {
cout << *it1 << " " ;
}
cout << endl;
}
class Person {
public :
Person (string name,int age) {
this ->m_Name = name;
this ->m_Age = age;
}
string m_Name;
int m_Age;
};
class comparePerson {
public :
bool operator () (const Person& p1, const Person& p2) const {
return p1. m_Age > p2. m_Age;
}
};
void test08 () {
set<Person,comparePerson>s1;
Person p1 ("懒羊羊" , 10 ) ;
Person p2 ("喜羊羊" , 13 ) ;
Person p3 ("费羊羊" , 14 ) ;
s1. insert (p1);
s1. insert (p2);
s1. insert (p3);
for (set<Person,comparePerson>::iterator it = s1. begin (); it != s1. end (); it++) {
cout << "name: " <<it->m_Name << " age: " <<it->m_Age << endl;
}
cout << endl;
}
五、Map / Multimap 容器
1. 基本概念
map 中所有元素都是 pair 对组
pair 中第一个元素为 key(键值),起到索引作用,第二个元素为 value(实值)
所有元素都会根据元素的键值(key)自动排序
本质:map / multimap 属于关联式容器,底层结构是用二叉树实现
优点:可以根据 key 值快速找到 value 值
map / multimap 区别:map 不允许容器中有重复 key 值元素,multimap 允许有重复的 key 值元素
2. Map 构造和赋值 map<T1,T2>mp;
map (const map &mp);
map&operator =(const map &mp);
void printMap (map<int , int >& mp) {
for (map<int , int >::iterator it = mp.begin (); it != mp.end (); it++) {
cout << "key = " << (*it).first << " value = " << it->second << endl;
}
cout << endl;
}
void test01 () {
map<int , int >mp;
mp.insert (pair <int , int >(1 , 10 ));
mp.insert (pair <int , int >(2 , 20 ));
mp.insert (pair <int , int >(3 , 30 ));
mp.insert (pair <int , int >(4 , 40 ));
mp.insert (pair <int , int >(5 , 50 ));
printMap (mp);
map<int , int >m2 (mp);
printMap (m2);
map<int , int >m3;
m3 = m2;
printMap (m3);
}
map 容器中所有元素都是成对出现的,所有元素插入时都得使用对组
3. Map 容大小和交换 size ();
empty ();
swap (mp);
void test02 () {
map<int , int >m1;
m1. insert (pair <int , int >(1 , 10 ));
m1. insert (pair <int , int >(2 , 20 ));
m1. insert (pair <int , int >(3 , 30 ));
m1. insert (pair <int , int >(4 , 40 ));
m1. insert (pair <int , int >(5 , 50 ));
if (m1. empty ()) {
cout << "the map vector is empty! " << endl;
} else {
cout << "the map vector is not empty!" << endl;
cout << "the map size is: " << m1. size () << endl;
}
map<int , int >m2;
m2. insert (pair <int , int >(5 , 50 ));
m2. insert (pair <int , int >(6 , 60 ));
m2. insert (pair <int , int >(7 , 70 ));
m2. insert (pair <int , int >(8 , 80 ));
m2. insert (pair <int , int >(9 , 90 ));
cout << "befor swap: " << endl;
printMap (m1);
printMap (m2);
m1. swap (m2);
cout << "after swap: " << endl;
printMap (m1);
printMap (m2);
}
4. Map 容器插入和删除 insert (elem);
clear ();
erase (pos);
erase (beg,end);
erase (key);
void test03 () {
map<int , int >m1;
m1. insert (pair <int , int >(1 , 10 ));
m1. insert (make_pair (2 , 20 ));
m1. insert (map<int , int >::value_type (3 , 30 ));
m1[4 ] = 40 ;
printMap (m1);
cout << m1[5 ] << endl;
m1. erase (m1. begin ());
m1. erase (3 );
m1. erase (m1. begin (), m1. end ());
m1. clear ();
}
不建议用 [] 插入值,但是可以用 key 访问到 value 值
5. Map 容器查找和统计 void test04 () {
map<int , int >m1;
m1. insert (make_pair (7 , 70 ));
m1. insert (pair <int , int >(6 , 60 ));
m1. insert (make_pair (8 , 80 ));
m1. insert (make_pair (9 , 90 ));
m1. insert (make_pair (5 , 50 ));
map<int , int >::iterator pos = m1.f ind(7 );
if (pos != m1. end ()) {
cout << "find it,the key is " << (*pos).first << " , the value is " << pos->second << endl;
} else {
cout << "cannot find it !" << endl;
}
cout << "the key is 3 have " << m1. count (3 ) << " 个" << endl;
}
map 容器中不允许插入重复的 key 的元素,第二个一样的 key 的值不会被插入,map 统计的结果只能是 0 或 1,multimap 的 count 统计可能大于 1.
6. Map 容器排序 sort()
class myCompare {
public :
bool operator () (int v1, int v2) const {
return v1 > v2;
};
};
void test05 () {
map < int , int ,myCompare > m1;
m1. insert (make_pair (7 , 70 ));
m1. insert (make_pair (9 , 90 ));
m1. insert (make_pair (6 , 60 ));
m1. insert (make_pair (5 , 50 ));
m1. insert (pair <int , int >(8 , 80 ));
for (map<int , int ,myCompare>::iterator it = m1. begin (); it != m1. end (); it++) {
cout << "key = " << (*it).first << " value = " << it->second << endl;
}
}
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Gemini 图片去水印 基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online