C++之STL容器详解(包含十种常用容器)

本文详细介绍了C++STL中的各种容器,如string、vector、set、queue、priority_queue、stack、dequeue、map、pair和bitset,涵盖了它们的创建、操作、特性和常见用途。
本文章已经生成可运行项目,

前言

C++的STL是提高编写效率的一个利器,是算法类竞赛必不可少的工具,本篇博客将详细总结C++STL的各种容器及其常用方法,包括:

  • string 类
  • vector 容器
  • set 容器
  • queue 容器
  • priority_queue 容器
  • stack 容器
  • dequeue 容器
  • map 容器
  • pair 容器
  • bitset 容器

一、string 类

string类本不是STL的容器,但是它与STL容器有着很多相似的操作,因此,把string放在这里一起进行介绍。C++中的string类相当于是字符数组,但是其更方便于我们的操作,而且不需要在输入之前初始化字符数组的容量,节省空间。

#include<string>

/*string 生成*/
string str("123"); //"123"
string str(3,"1"); //"111"
string str = "123"; //"123"

/*string 头尾*/
str.front(); //第一个元素 
str.back(); //最后一个元素 

/*string 迭代器*/
string::iterator iter //一个string的迭代器
str.begin() //指向str第一个元素位置的迭代器 
str.end() //指向str最后一个元素后一个位置的迭代器 

/*string 插入*/
str.push_back('a'); //在尾部插入一个字符
str.insert(s1.begin(), 'a'); //在指定位置前面插入一个字符

/*string 删除*/
str.pop_back(); //删除最后一个元素 
str.erase(str.begin()); //删除迭代器指向元素
str.erase(str.begin()+1, str.end()-2); //删除指定区间的元素
str.erase(1, 6); //删除从索引(1)开始的n(6)个字符

/*string 替换*/
str.replace(str.begin(), str.begin + 5, "boy"); //替换迭代器指定的区间
str.replace(6, 5, "girl"); //替换索引指定的区间,从下标6开始的五个元素 

/*string 拼接*/
str1.append(str2); //str1str2
str1 = str1 + str2; //str1str2

/*string 容量*/
str.size()
str.length()

/*string 遍历*/
for(int i = 0; i < str.size(); i ++ ) //索引遍历 
for(string::iterator iter = str.begin(); iter != str.end(); iter ++ ) //迭代器遍历 
for(auto &x : str) //迭代器另一种便捷方法 

/*string 排序*/
sort(str.begin(), str.end());

/*string 比较*/
str1 < str2 //字典序比较,<、<=、==、>、>=都可以用
str1.compare(str2) //相等为0,str1>str2为1,反之-1

/*sting 查找*/
str.find("123") //从前往后找,若找到,返回首字母下标;反之,返回-1
str.rfind("123") //从后往前找
str.find_first_of("123") //查找第一个属于该字符串的字符返回下标
str.find_first_not_of("123")
str.find_last_of("123")
str.find_last_not_of("123")

/*string 某元素个数*/
str.count('a'); //返回str里a字符的个数 

/*string 分割*/
str.substr(2, 5); //返回从索引2开始的五个元素组成的字符串 

/*string 判空*/
str.empty() //返回布尔值 

/*string 清空*/
str.clear();

二、vector 容器

vector是变长数组(节省空间),支持随机访问,不支持在任意位置 O(1) 插入。为了保证效率,元素的增删一般应该在末尾进行。(以下typename均用int举例)

#include <vector>

/*vector 生成*/
vector<int> vct(3); //0 0 0
vector<int> vct(3, 5); //5 5 5
vector<int> vct{1, 2, 3}; //1 2 3

/*vector 头尾*/
vct.front(); //第一个元素 
vct.back(); //最后一个元素 

/*vector 迭代器*/
vector<int>::iterator iter //一个vector的迭代器
vct.begin() //指向vct第一个元素位置的迭代器 
vct.end() //指向vct最后一个元素后一个位置的迭代器

/*vector 插入*/
vct.push_back(2); //在尾部插入一个2
vct.insert(vct.begin(), 2); //在指定位置前面插入一个元素

/*vector 删除*/
vct.pop_back();
vct.erase(vct.begin());
vct.erase(vct.begin()+1, vct.end()-2);
vct.erase(1, 6);

/*vector 容量*/
vct.size()

/*vector 遍历*/
for(int i = 0; i < vct.size(); i ++ ) //索引遍历 
for(vector<int>::iterator iter = vct.begin(); iter != vct.end(); iter ++ ) //迭代器遍历 
for(auto &x : vct) //迭代器另一种便捷方法 

/*vector 排序*/
sort(vct.begin(), vct.end());

/*vctor 查找*/
vct.find(2) //从前往后找,若找到,返回指向该处的迭代器;反之,返回迭代器vct.end()

/*vctor 某元素个数*/
vct.count(2); //返回容器里2的个数 

/*vector 判空*/
vct.empty() //返回布尔值 

/*vector 清空*/
vct.clear();

三、set 容器

头文件set主要包括set和multiset(两者方法相同,所以以下只用set举例)两个容器,分别是“有序集合”和“有序多重集合”,即前者的元素不能重复,而后者可以包含若干个相等的元素,两者都会将其容器内的元素从小到大自动排序。set和multiset的内部实现是一棵红黑树,它们支持的函数基本相同。(下typename均用int举例)

#include <set>

/*set 生成*/
set<int> st;

/*set 迭代器*/
set<int>::iterator iter 
st.begin() 
st.end() 

/*set 插入*/
st.insert(2); //插入一个元素

/*set 删除*/
st.erase(st.begin()); //删除迭代器指向元素 
st.erase(2); //删除所有为2的元素 

/*set 容量*/
st.size()

/*set 查找*/
st.find(2) //从前往后找,若找到,返回指向该处的迭代器;反之,返回迭代器st.end()
st.lower_bound(x) //二分查找大于等于x的元素中最小的一个,并返回指向该元素的迭代器。
st.upper_bound(x) //二分查找大于x的元素中最小的一个,并返回指向该元素的迭代器。

/*set 某元素个数*/
st.count(2); //返回容器里2的个数

/*set 判空*/
st.empty() //返回布尔值 

/*set 清空*/
st.clear();

四、queue 容器

头文件queue主要包括循环队列queue和优先队列priority_queue两个容器。其中queue容器相当于队列,满足先进先出的原则,即队尾出、队首进。(以下typename均用int举例)

#include <queue>

/*queue 生成*/
queue<int> q;

/*queue 头尾*/
q.front();
q.back();

/*queue 插入*/
q.push(2); //在队尾插入一个元素 

/*queue 删除*/
q.pop(); //在队首删除一个元素

/*queue 容量*/
q.size();

/*queue 判空*/
q.empty()

五、priority_queue 容器

头文件queue主要包括循环队列queue和优先队列priority_queue两个容器。其中priority_queue容器相当于大根堆(或者小根堆),大根堆每次堆顶是最大元素,小根堆每次堆顶是最小元素。(以下typename均用int举例)

#include <queue>

/*priority_queue 生成*/
priority_queue<int> q; //大根堆
priority_queue<int, vector<int>, greater<int>> q; //小根堆

/*priority_queue 插入*/
q.push(2); //把一个元素插入堆 

/*priority_queue 删除*/
q.pop(); //删除堆顶的元素 

/*priority_queue 堆顶*/
q.top(); //返回堆顶元素 

/*priority_queue 容量*/
q.size();

/*priority_queue 判空*/
q.empty()

六、stack 容器

stack容器相当于栈,满足先进后出的原则,即插入和删除都只能再栈顶操作。(以下typename均用int举例)

#include <stack>

/*stack 生成*/
stack<int> sk;

/*stack 插入*/
sk.push(2); //把一个元素放入栈 

/*stack 删除*/
sk.pop(); //删除栈顶的元素 

/*stack 栈顶*/
sk.top(); //返回栈顶元素 

/*stack 容量*/
sk.size();

/*stack 判空*/
sk.empty()

七、dequeue 容器

双端队列deque是一个支持在两端高效插入或删除元素的连续线性存储空间。它就像是vector和queue的结合。与vector相比,deque在头部增删元素仅需要 O(1)的时间;与queue相比,deque像数组一样支持随机访问。(以下typename均用int举例)

#include <deque>

/*dequeue 生成*/
dequeue<int> dq;

/*dequeue 头尾*/
dq.front();
dq.back();

/*dequeue 迭代器*/
dq.begin() 
dq.end()

/*dequeue 插入*/
dq.push_front(2); //头插入 
dq.push_back(2); //尾插入 

/*dequeue 删除*/
dq.pop_front(); //头删除 
dq.pop_back(); //尾删除 

/*dequeue 容量*/
dq.size();

/*dequeue 判空*/
dq.empty()

/*dequeue 清空*/
dq.clear();

八、map 容器

map容器是一个键值对key-value的映射,其内部实现是一棵以key为关键码的红黑树。map的key和value可以是任意类型。(以下typename均用int举例)

#include <map>

/*map 生成*/
map<key_type, value_type> name;
map<int, int> mp;

/*map 迭代器*/
map<int, int>::iterator iter
mp.begin() 
mp.end() 

/*map 键值*/
iter->first //key
iter->second //value

/*map 插入*/
mp[2] = 5; //直接添加
mp.insert(pair<int, int>(2, 5)); //insert一个pair

/*删除*/
mp.erase(iter); //删除迭代器所指的键值对 

/*map 容量*/
mp.size()

/*map 查找*/
mp.find(2) //从前往后找,若找到,返回指向该处的迭代器;反之,返回迭代器mp.end()

/*map 某元素个数*/
st.count(2); //返回key为2的个数(map中只可能是0或者1) 

/*map 判空*/
mp.empty() //返回布尔值 

/*map 清空*/
mp.clear();

九、pair 容器

pair相当于将两份数据打包成一对,两份数据的数据类型任意,多与其他容器混合使用,单独使用的情况比较少。(以下typename均用int举例)

#include <utility>

/*pair 生成*/
pair<int, int> pr = make_pair(0,1);
pair<int, int> pr(0, 1);

/*pair 两个值*/
pr.first 
pr.second 

/*pair 多与其他容器结合使用*/
set<pair<int, int>> st;
vector<pair<int, int>> vct(mp.begin(), mp.end());

十、bitset 容器

bitset容器相当于是01数组,其方便之处是可以直接按位(下标)进行位运算,但是要注意下标从小到大依次存低位到高位,是逆序的。

#include<bitset>

/*bitset 生成*/
bitset<4> bt; //生成4位二进制数,初始化为0000
bitset<8> bt(12); //生成8位二进制数,且将10进制数12转化为2进制数存入其中
bitset<8> bt(str); //str可以是只有01的字符串或者字符数组

/*bitset 位运算相关*/
bt1 |= bt2; //两个二进制数取或操作 
bt1 &= bt2; //两个二进制数取与操作 
bt1 ^= bt2; //取异或
bt1 = ~bt1; //取反
bt1 <<= x; //左移右移 
 
bt.test(x) //判断第x个位置是0还是1,也就是输出第x个位置,注意逆序

bt.flip(); //将二进制每一位取反
bt.flip(x); //将二进制第x位取反
bt.set(); //将二进制每一位置为1 
bt.set(x); //将第x个位置置为1
bt.reset(); //将二进制每一位置为0
bt.reset(x); //将第x个位置置为0

/*bitset 容量*/
bt.size() //二进制数组的长度,就是定义的长度;

/*bitset 某元素个数*/
bt.count(); //查询二进制数组中,1的个数

/*bitset 转化字符串*/
string str = bt.to_string(); //将二进制数组转化为字符串。 

本文已生成可运行项目
<think>首先,用户的问题是:“我想了解或学习C++ STL容器的使用和特性 请问C++ STL 容器类型 使用方法 特性”。用户想了解C++ STL容器的类型、使用方法和特性。 根据系统级指令: - 所有行内数学表达式必须使用$...$格式。 - 独立公式必须使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识,例如[^1]。 - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 参考的引用: - [^1]: 介绍了STL的基本概念、六大组件(容器算法、迭代器、仿函数、适配器、空间配置器)。 - [^2]: 讨论了vector容器的动态分配特性。 - [^3]: 提到了map容器的内部实现(红黑树)和性能特点。 - [^4]: 提供了容器操作如size(), empty(), count(), lower_bound(), upper_bound(), begin(), end()。 我需要构建一个清晰的回答结构: 1. **介绍STL容器**:简要解释什么是STL容器及其在STL中的角色。 2. **主要容器类型**:列出并描述常见的STL容器类型(如vector, list, deque, set, map等)。 3. **使用方法**:解释如何声明、初始化和使用这些容器,包括常见操作。 4. **特性**:讨论每个容器的特性,如性能、内存管理等。 5. **生成相关问题**:在最后添加相关问题。 使用中文回答,并确保内容真实可靠。 结构大纲: - **引言**:介绍STL容器。 - **容器类型分类**:将容器分为序列容器、关联容器等。 - **详细容器描述**:为每个主要容器提供: - 类型 - 使用方法(代码示例) - 特性 - **总结**:简要总结。 - **相关问题**:生成几个相关问题。 在引用时,自然地添加引用标识。例如,如果提到vector的动态分配,引用[^2]。 LaTeX:如果涉及数学表达式,如时间复杂度,使用$...$或$$...$$。例如,时间复杂度$O(1)$。 代码示例:使用代码块展示使用方法。 最终,添加相关问题。</think>### C++ STL 容器使用与特性详解 C++ STL(Standard Template Library)提供了一系列高效、可重用的容器类,用于存储和管理数据。容器STL的核心组件之一,与算法和迭代器无缝集成[^1]。下面我将从容器类型、使用方法和特性三个方面,逐步介绍STL容器,确保内容清晰可靠。 #### 1. **STL容器类型概述** STL容器分为两大类:序列容器和关联容器。序列容器强调元素的顺序存储,关联容器则基于键值对存储以实现快速查找。常用容器包括: - **序列容器**:`vector`、`list`、`deque`。 - **关联容器**:`set`、`map`、`multiset`、`multimap`。 - **其他容器**:`stack`、`queue`(适配器容器)。 每个容器都基于特定数据结构实现,影响其性能和适用场景。 #### 2. **容器使用方法** 容器使用需包含头文件(如`<vector>`),并通过模板类声明。常用操作包括插入、删除、访问和遍历。以下以典型容器为例,展示基本用法(代码示例使用C++语法)。 - **vector(动态数组)** 使用方法: ```cpp #include <vector> #include <iostream> int main() { std::vector<int> vec; // 声明一个int类型的vector vec.push_back(10); // 尾部插入元素 vec.push_back(20); vec.pop_back(); // 删除尾部元素 std::cout << "第一个元素: " << vec[0] << std::endl; // 随机访问 // 遍历 for (auto it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; } return 0; } ``` 特性: - 动态数组,内存连续,支持随机访问(时间复杂度$O(1)$)。 - 添加元素时可能触发内存重新分配(默认分配额外空间,如初始32个元素大小),尾部插入平均$O(1)$,头部插入$O(n)$[^2]。 - 适用场景:频繁随机访问、尾部操作,但避免在中间插入。 - **map(键值对容器)** 使用方法: ```cpp #include <map> #include <iostream> int main() { std::map<std::string, int> myMap; // 声明键为string、值为int的map myMap["apple"] = 5; // 插入键值对 myMap.insert(std::make_pair("banana", 3)); myMap.erase("apple"); // 删除键 // 查找和遍历 auto it = myMap.find("banana"); if (it != myMap.end()) { std::cout << "值: " << it->second << std::endl; } return 0; } ``` 特性: - 基于红黑树实现,元素自动排序(键唯一),查找、插入、删除时间复杂度均为$O(\log n)$[^3]。 - 每个节点占用额外内存(约16字节,用于树结构),空间开销较大。 - 适用场景:需键值对映射和快速查找的场景,如字典或配置管理。 - **set(唯一元素集合)** 使用方法: ```cpp #include <set> int main() { std::set<int> mySet; mySet.insert(30); mySet.insert(10); mySet.erase(10); // 删除元素 // 使用迭代器遍历 for (auto elem : mySet) { std::cout << elem << " "; } return 0; } ``` 特性: - 类似map,但只存储键,元素唯一且有序。 - 时间复杂度与map相同,为$O(\log n)$[^4]。 - **list(双向链表)** 使用方法: ```cpp #include <list> int main() { std::list<int> myList; myList.push_back(1); // 尾部插入 myList.push_front(2); // 头部插入 myList.pop_front(); // 删除头部 return 0; } ``` 特性: - 链表结构,插入/删除任意位置$O(1)$,但访问$O(n)$。 - 无连续内存,适合频繁插入删除的场景。 #### 3. **通用特性与操作** 所有STL容器共享一些通用操作: - **大小管理**:`size()` 返回元素数量,`empty()` 检查是否为空。 - **迭代器访问**:`begin()` 和 `end()` 提供迭代器用于遍历。 - **查找操作**:关联容器支持 `find(key)`、`count(elem)`(返回元素出现次数),以及 `lower_bound(elem)` 和 `upper_bound(elem)` 用于范围查询(返回迭代器位置)[^4]。 - **性能特点**: - 序列容器(如vector)在尾部操作高效,关联容器(如map)在查找上占优。 - 时间复杂度总结:随机访问容器(vector、deque)为$O(1)$,链表(list)为$O(n)$,树基容器(set、map)为$O(\log n)$。 - **内存管理**:容器自动处理内存,但需注意动态分配的开销(如vector的预分配策略减少重新分配次数)[^2]。 #### 4. **选择容器的建议** - 需要快速随机访问?选 `vector` 或 `deque`。 - 频繁插入删除?选 `list` 或关联容器。 - 需键值对映射?选 `map`。 - 性能关键时,优先使用容器自带函数(如 `map::find` 优于通用算法),以利用内部优化[^3]。 STL容器通过模板提供类型安全性和泛型编程能力,是现代C++高效开发的基础。结合算法(如 `sort`)和迭代器,可实现复杂数据处理[^1]。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值