c++ 顺序容器概述
C++ 中的顺序容器是标准模板库(STL)的一部分,它提供了一组用于存储和管理对象序列的模板类。这些容器在内存中以线性顺序存储元素,允许快速顺序访问。顺序容器的主要类型包括:
vector:动态数组,支持快速随机访问。在向量的末尾添加或删除元素比较高效,但在中间或开头插入或删除元素可能较慢。
deque(双端队列):与 vector 类似,但设计用于在两端快速插入和删除元素。
list:双向链表,支持在任何位置快速插入和删除元素,但不支持快速随机访问。
forward_list:单向链表,与 list 类似,但仅支持向前遍历。相比 list,它使用更少的内存。
array:固定大小的数组。它提供与内置数组类似的功能,但增加了一些额外的功能,如 STL 兼容的迭代器。
string:专门用于字符的容器,提供了对字符串进行操作的丰富功能。
容器通用操作
在 C++ 中,标准模板库(STL)提供了多种容器,每种容器都支持一些通用操作。下面是这些操作的详细介绍
1. 构造和析构
构造:容器可以通过多种方式构造,如默认构造、复制构造、范围构造等。
析构:容器对象离开其作用域时,其析构函数会被自动调用,释放所有资源。
示例:std::vector 的构造
std::vector<int> vec1; // 默认构造 std::vector<int> vec2 = {1, 2, 3, 4, 5}; // 初始化列表构造 std::vector<int> vec3(vec2); // 复制构造
2. 迭代器操作
begin() 和 end():返回指向容器第一个元素和尾后元素的迭代器。
rbegin() 和 rend():返回反向迭代器。
示例:使用迭代器遍历 std::vector
for(auto it = vec2.begin(); it != vec2.end(); ++it) { std::cout << *it << " "; }
3. 容量查询
empty():检查容器是否为空。
size():返回容器中元素的数目。
示例:检查 std::vector 的大小
std::cout << "Is empty: " << vec1.empty() << "\n"; std::cout << "Size: " << vec2.size() << "\n";
4. 元素访问
operator[] 或 at():用于访问元素。
front() 和 back():访问第一个和最后一个元素。
示例:访问 std::vector 的元素
std::cout << "First element: " << vec2.front() << "\n"; std::cout << "Last element: " << vec2.back() << "\n";
5. 修改操作
insert():在指定位置插入元素。
erase():删除一个或一范围的元素。
push_back() 和 pop_back():在末尾添加和移除元素。
示例:修改 std::vector
vec2.push_back(6); // 在末尾添加元素 vec2.erase(vec2.begin()); // 移除第一个元素
完整代码示例
下面是一个综合示例,综合了上述所有操作。
#include <iostream> #include <vector> int main() { // 使用初始化列表构造向量 std::vector<int> vec = {1, 2, 3, 4, 5}; // 输出原始向量 std::cout << "Original vector: "; for(const auto& value : vec) { std::cout << value << " "; } std::cout << "\\n"; // 检查向量是否为空并输出大小 std::cout << "Is empty: " << vec.empty() << "\\n"; std::cout << "Size: " << vec.size() << "\\n"; // 输出第一个和最后一个元素 std::cout << "First element: " << vec.front() << "\\n"; std::cout << "Last element: " << vec.back() << "\\n"; // 修改向量 vec.push_back(6); // 在末尾添加元素 vec.erase(vec.begin()); // 移除第一个元素 // 输出修改后的向量 std::cout << "Modified vector: "; for(const auto& value : vec) { std::cout << value << " "; } std::cout << std::endl; return 0; }
输出:
Original vector: 1 2 3 4 5 Is empty: 0 Size: 5 First element: 1 Last element: 5 Modified vector: 2 3 4 5 6
- 原始向量:打印了初始向量中的元素(1 2 3 4 5)。
- 容器状态查询:
- 向量非空(Is empty: 0,0 表示 false)。
- 向量的初始大小为 5。
- 元素访问:
- 第一个元素是 1。
- 最后一个元素是 5。
- 修改向量:
- 向量末尾添加了一个元素 6。
- 从向量开头移除了第一个元素(原来的 1)。
- 修改后的向量:最终,修改后的向量元素为 2 3 4 5 6。
迭代器
1. 迭代器的概念和类型
概念:迭代器是一个允许程序员在容器(如数组或STL容器)上进行遍历的对象。它类似于指针,但提供了更高层次的抽象。
类型:
- 输入迭代器:仅用于从容器中读取数据。
- 输出迭代器:仅用于向容器写入数据。
- 前向迭代器:用于单向读写操作。
- 双向迭代器:支持向前和向后遍历。
- 随机访问迭代器:支持直接访问任意元素,类似数组。
2. 迭代器的操作
操作:
- 解引用:通过 *iterator 访问迭代器指向的元素。
- 自增:++iterator 移动到下一个元素。
- 自减:对于双向迭代器,--iterator 移动到前一个元素。
- 比较:使用 == 和 != 比较迭代器。
示例:使用迭代器遍历 std::vector
std::vector<int> vec = {1, 2, 3, 4, 5}; for(std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; }
3. 迭代器的高级应用
应用:迭代器用于容器的许多操作,如插入、删除元素。
示例:使用迭代器进行插入和删除
vec.insert(vec.begin() + 2, 6); // 在第三个元素前插入 6 vec.erase(vec.begin()); // 删除第一个元素
4. 注意事项
注意:
- 容器被修改时,迭代器可能失效。
- 某些容器(如 std::list)不支持随机访问迭代器。
完整代码示例
#include <iostream> #include <vector> int main() { // 创建一个 vector std::vector<int> vec = {1, 2, 3, 4, 5}; // 使用迭代器遍历并打印元素 std::cout << "Original vector: "; for(auto it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; } std::cout << "\\n"; // 使用迭代器插入元素 vec.insert(vec.begin() + 2, 6); // 使用迭代器删除元素 vec.erase(vec.begin()); // 再次打印修改后的 vector std::cout << "Modified vector: "; for(const auto& value : vec) { std::cout << value << " "; } std::cout << std::endl; return 0; }
输出:
Original vector: 1 2 3 4 5 Modified vector: 2 3 6 4 5
容器定义和初始化
- std::vector
定义:std::vector 是一个动态数组,可以存储任意数量的同类型元素。
初始化:
空的 vector:std::vector vec;
初始化列表:std::vector vec = {1, 2, 3, 4, 5};
指定大小和初始值:std::vector vec(10, 0);(10个元素,每个都是0)std::list
std::list
定义:std::list 是一个双向链表,适用于频繁的插入和删除操作。
初始化:
空的 list:std::list lst;
初始化列表:std::list lst = {1, 2, 3, 4, 5};
std::map
定义:std::map 是一个基于键-值对的关联容器,每个键都是唯一的。
初始化:
空的 map:std::map mp;
初始化列表:std::map mp = {{1, "one"}, {2, "two"}};
示例代码
以下是一些容器定义和初始化的示例代码。
#include <iostream> #include <vector> #include <list> #include <map> int main() { // Vector 初始化 std::vector<int> vec = {1, 2, 3, 4, 5}; std::cout << "Vector: "; for(const int& i : vec) { std::cout << i << " "; } std::cout << "\\n"; // List 初始化 std::list<int> lst = {1, 2, 3, 4, 5}; std::cout << "List: "; for(const int& i : lst) { std::cout << i << " "; } std::cout << "\\n"; // Map 初始化 std::map<int, std::string> mp = {{1, "one"}, {2, "two"}}; std::cout << "Map: "; for(const auto& pair : mp) { std::cout << pair.first << "->" << pair.second << " "; } std::cout << std::endl; return 0; }
解释
std::vector vec = {1, 2, 3, 4, 5};
这行代码创建了一个 std::vector,并使用初始化列表 {1, 2, 3, 4, 5} 进行初始化。
std::list lst = {1, 2, 3, 4, 5};
类似地,这行代码创建了一个 std::list 并使用同样的初始化列表。
std::map mp = {{1, "one"}, {2, "two"}};
这里创建了一个 std::map,其中每个元素都是一个键-值对。
C++ 容器赋值和 Swap
在 C++ 标准模板库(STL)中,容器支持赋值操作和 swap 函数。这些操作是容器类的基本功能,允许容器间的内容交换和赋值。以下是这些操作的详细介绍:
1. 赋值操作
赋值:容器可以使用赋值操作符(=)将一个容器的内容复制到另一个容器中。
示例:std::vector 的赋值
std::vector<int> vec1 = {1, 2, 3}; std::vector<int> vec2; vec2 = vec1; // 将 vec1 的内容赋值给 vec2
2. Swap 操作
swap():swap 函数交换两个同类型容器的内容。这是一个非常高效的操作,通常只交换容器内部的指针,而不是复制整个容器的数据。
示例:使用 swap 交换 std::vector 的内容
std::vector<int> vec3 = {4, 5, 6}; vec1.swap(vec3); // 交换 vec1 和 vec3 的内容
完整代码示例
下面是一个综合示例,演示了赋值和 swap 操作。
#include <iostream> #include <vector> int main() { std::vector<int> vec1 = {1, 2, 3}; std::vector<int> vec2; std::vector<int> vec3 = {4, 5, 6}; // 赋值操作 vec2 = vec1; // 将 vec1 的内容赋值给 vec2 // 输出赋值后的 vec2 std::cout << "After assignment, vec2: "; for(const auto& value : vec2) { std::cout << value << " "; } std::cout << "\\n"; // Swap 操作 vec1.swap(vec3); // 交换 vec1 和 vec3 的内容 // 输出 swap 后的 vec1 和 vec3 std::cout << "After swap, vec1: "; for(const auto& value : vec1) { std::cout << value << " "; } std::cout << "\\n"; std::cout << "After swap, vec3: "; for(const auto& value : vec3) { std::cout << value << " "; } std::cout << std::endl; return 0; }
输出:
After assignment, vec2: 1 2 3 After swap, vec1: 4 5 6 After swap, vec3: 1 2 3
- 赋值操作:将 vec1 的内容赋值给 vec2,使得 vec2 的内容变为 1 2 3。
- Swap 操作:交换 vec1 和 vec3 的内容,使得 vec1 的内容变为 4 5 6,而 vec3 的内容变为 1 2 3。
容器大小操作
在 C++ 标准模板库(STL)中,容器提供了多种操作来管理和查询其大小。这些操作允许你检查容器是否为空,获取容器的大小,调整容器的大小,以及在容器的末尾添加或删除元素。以下是这些操作的详细介绍:
1. 检查是否为空
empty():这个函数用于检查容器是否为空(即不包含任何元素)。
示例:检查 std::vector 是否为空
std::vector<int> vec; bool isEmpty = vec.empty(); // 检查 vec 是否为空
2. 获取大小
size():返回容器中元素的数量。
示例:获取 std::vector 的大小
std::vector<int> vec = {1, 2, 3}; size_t size = vec.size(); // 获取 vec 的大小
3. 改变大小
resize():改变容器的大小。如果新大小大于当前大小,则在容器末尾添加元素。如果新大小小于当前大小,则从容器末尾删除元素。
示例:改变 std::vector 的大小
vec.resize(5); // 改变 vec 的大小为 5
4. 添加和删除元素
push_back():在容器末尾添加一个新元素。
pop_back():删除容器末尾的元素。
示例:在 std::vector 中添加和删除元素
vec.push_back(4); // 在 vec 末尾添加元素 4 vec.pop_back(); // 删除 vec 末尾的元素
完整代码示例
下面是一个综合示例,演示了上述所有大小操作。
#include <iostream> #include <vector> int main() { std::vector<int> vec = {1, 2, 3}; // 检查是否为空 std::cout << "Is empty: " << vec.empty() << "\\n"; // 获取大小 std::cout << "Size before resize: " << vec.size() << "\\n"; // 改变大小 vec.resize(5); // 改变 vec 的大小为 5 // 输出改变大小后的 vec std::cout << "Size after resize: " << vec.size() << "\\n"; std::cout << "Elements: "; for(const auto& value : vec) { std::cout << value << " "; } std::cout << "\\n"; // 添加和删除元素 vec.push_back(4); // 添加元素 vec.pop_back(); // 删除元素 // 输出最终的 vec std::cout << "Final elements: "; for(const auto& value : vec) { std::cout << value << " "; } std::cout << std::endl; return 0; }
输出:
Is empty: 0 Size before resize: 3 Size after resize: 5 Elements: 1 2 3 0 0 Final elements: 1 2 3 0 0
- 检查是否为空:vec 不为空(Is empty: 0,0 表示 false)。
- 获取大小:初始 vec 的大小为 3。
- 改变大小:改变后的 vec 大小为 5,多出的位置用默认值 0 填充。
- 添加和删除元素:添加了一个元素 4 然后又删除了,所以最终元素没有变化。
顺序容器操作
在 C++ 的标准模板库(STL)中,顺序容器如 vector、deque、list 等提供了一系列操作,使得元素的管理和访问变得灵活高效。以下是顺序容器的一些常用操作的详细介绍:
1. 访问元素
operator[] 和 at():用于访问指定位置的元素。at() 方法与 operator[] 相似,但它会检查索引是否越界。
示例:访问 std::vector 中的元素
std::vector<int> vec = {1, 2, 3}; int firstElement = vec[0]; // 使用 operator[] int secondElement = vec.at(1); // 使用 at()
2. 前后元素访问
front() 和 back():分别返回容器中的第一个和最后一个元素的引用。
示例:访问 std::vector 的第一个和最后一个元素
int first = vec.front(); // 第一个元素 int last = vec.back(); // 最后一个元素
3. 迭代器
begin(), end(), rbegin(), rend():分别返回指向容器第一个元素、尾后元素的迭代器,以及对应的反向迭代器。
示例:遍历 std::vector
for(auto it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; }
4. 修改容器
insert(), erase(), push_back(), pop_back(), clear():用于在容器中插入和删除元素。
示例:修改 std::vector
vec.push_back(4); // 添加元素 vec.erase(vec.begin()); // 删除第一个元素 vec.clear(); // 清空容器
5. 容器大小
size(), empty(), resize():获取容器的大小,检查是否为空,或者改变容器的大小。
示例:检查 std::vector 的大小和状态
bool isEmpty = vec.empty(); // 检查是否为空 size_t size = vec.size(); // 获取大小 vec.resize(3); // 调整大小
完整代码示例
下面是一个综合示例,展示了上述所有操作。
#include <iostream> #include <vector> int main() { std::vector<int> vec = {1, 2, 3}; // 访问元素 std::cout << "First element: " << vec[0] << ", Second element: " << vec.at(1) << "\\n"; // 前后元素访问 std::cout << "Front: " << vec.front() << ", Back: " << vec.back() << "\\n"; // 遍历容器 std::cout << "Elements: "; for(auto it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; } std::cout << "\\n"; // 修改容器 vec.push_back(4); vec.erase(vec.begin()); vec.clear(); // 容器大小操作 std::cout << "Is empty: " << vec.empty() << "\\n"; std::cout << "Size: " << vec.size() << "\\n"; vec.resize(3); return 0; }
输出:
Fir
c++顺序容器(二)https://developer.aliyun.com/article/1437162?spm=a2c6h.13262185.profile.37.5bba685cuSQkDD