【C++ Primer】第九章:顺序容器
·
这一章主要讲解顺序容器,包括vector、deque、list、array等,这是C++标准库中非常重要的组成部分。能把代码过一遍最好,过不了收藏起来也是不错的。
9.1 顺序容器概述
容器类型和选择
#include <iostream>
#include <vector>
#include <list>
#include <deque>
#include <array>
#include <string>
using std::cout;
using std::endl;
using std::string;
void containerOverview() {
cout << "=== 顺序容器概述 ===" << endl;
// 1. vector - 动态数组,快速随机访问,尾部插入删除高效
std::vector<int> vec = {1, 2, 3, 4, 5};
cout << "vector: ";
for (auto v : vec) cout << v << " ";
cout << endl;
// 2. list - 双向链表,任何位置插入删除高效,不支持随机访问
std::list<string> lst = {"apple", "banana", "cherry"};
cout << "list: ";
for (const auto& item : lst) cout << item << " ";
cout << endl;
// 3. deque - 双端队列,头尾插入删除高效,支持随机访问
std::deque<double> dq = {1.1, 2.2, 3.3};
cout << "deque: ";
for (auto d : dq) cout << d << " ";
cout << endl;
// 4. array - 固定大小数组,大小编译时确定
std::array<int, 4> arr = {10, 20, 30, 40};
cout << "array: ";
for (auto a : arr) cout << a << " ";
cout << endl;
// 5. forward_list - 单向链表(C++11),内存开销更小
std::forward_list<char> flst = {'a', 'b', 'c'};
cout << "forward_list: ";
for (auto c : flst) cout << c << " ";
cout << endl;
}
void containerSelection() {
cout << "\n=== 容器选择指南 ===" << endl;
// 通常首选vector
cout << "通常情况: 首选 vector" << endl;
std::vector<int> numbers;
for (int i = 0; i < 10; ++i) {
numbers.push_back(i * i);
}
// 需要频繁在中间插入删除:使用list
cout << "频繁中间操作: 使用 list" << endl;
std::list<int> middleHeavy;
for (int i = 0; i < 5; ++i) {
middleHeavy.push_back(i);
}
// 需要频繁在头尾插入删除:使用deque
cout << "频繁头尾操作: 使用 deque" << endl;
std::deque<int> endHeavy;
endHeavy.push_back(100);
endHeavy.push_front(200);
// 固定大小:使用array
cout << "固定大小: 使用 array" << endl;
std::array<std::string, 3> fixedArray = {"固定", "大小", "数组"};
}
int main() {
containerOverview();
containerSelection();
return 0;
}
9.2 容器库概览
容器操作
#include <iostream>
#include <vector>
#include <list>
#include <string>
using std::cout;
using std::endl;
using std::string;
void containerOperations() {
cout << "=== 容器通用操作 ===" << endl;
// 类型别名
std::vector<int> vec = {1, 2, 3, 4, 5};
// 迭代器类型
std::vector<int>::iterator it = vec.begin();
std::vector<int>::const_iterator cit = vec.cbegin();
// 大小操作
cout << "大小: " << vec.size() << endl;
cout << "最大大小: " << vec.max_size() << endl;
cout << "是否为空: " << vec.empty() << endl;
// 添加删除元素
vec.push_back(6);
vec.pop_back();
// 比较操作
std::vector<int> vec2 = {1, 2, 3, 4, 5};
cout << "vec == vec2: " << (vec == vec2) << endl;
cout << "vec < vec2: " << (vec < vec2) << endl;
}
void iteratorOperations() {
cout << "\n=== 迭代器操作 ===" << endl;
std::vector<string> words = {"hello", "world", "c++", "programming"};
// 迭代器遍历
cout << "正向遍历: ";
for (auto it = words.begin(); it != words.end(); ++it) {
cout << *it << " ";
}
cout << endl;
// 反向迭代器
cout << "反向遍历: ";
for (auto rit = words.rbegin(); rit != words.rend(); ++rit) {
cout << *rit << " ";
}
cout << endl;
// 常量迭代器
cout << "常量迭代器遍历: ";
for (auto cit = words.cbegin(); cit != words.cend(); ++cit) {
// *cit = "changed"; // 错误!不能通过常量迭代器修改
cout << *cit << " ";
}
cout << endl;
}
void containerTypes() {
cout << "\n=== 容器类型成员 ===" << endl;
std::list<double> lst = {1.5, 2.5, 3.5};
// 使用类型成员
std::list<double>::value_type val = 4.5; // double
std::list<double>::reference ref = lst.front(); // double&
std::list<double>::const_reference cref = lst.back(); // const double&
std::list<double>::size_type size = lst.size(); // size_t
cout << "值类型示例: " << val << endl;
cout << "引用类型示例: " << ref << endl;
cout << "大小类型示例: " << size << endl;
}
int main() {
containerOperations();
iteratorOperations();
containerTypes();
return 0;
}
9.3 顺序容器操作
添加元素
#include <iostream>
#include <vector>
#include <list>
#include <deque>
#include <string>
using std::cout;
using std::endl;
using std::string;
void addingElements() {
cout << "=== 添加元素操作 ===" << endl;
// push_back - 在尾部添加元素
std::vector<int> vec;
for (int i = 0; i < 5; ++i) {
vec.push_back(i * 10);
}
cout << "push_back后: ";
for (auto v : vec) cout << v << " ";
cout << endl;
// push_front - 在头部添加元素(vector没有push_front)
std::list<int> lst;
for (int i = 0; i < 5; ++i) {
lst.push_front(i * 10); // 注意:会逆序
}
cout << "push_front后: ";
for (auto l : lst) cout << l << " ";
cout << endl;
// insert - 在指定位置插入元素
std::vector<string> words = {"hello", "world"};
auto it = words.begin() + 1;
words.insert(it, "beautiful");
cout << "insert后: ";
for (const auto& w : words) cout << w << " ";
cout << endl;
// 插入多个元素
words.insert(words.end(), 2, "!");
cout << "插入多个相同元素后: ";
for (const auto& w : words) cout << w << " ";
cout << endl;
// 插入范围
std::vector<string> newWords = {"wonderful", "amazing"};
words.insert(words.begin() + 1, newWords.begin(), newWords.end());
cout << "插入范围后: ";
for (const auto& w : words) cout << w << " ";
cout << endl;
// emplace操作 - 直接构造元素,避免拷贝
std::vector<std::pair<int, string>> pairs;
pairs.emplace_back(1, "one"); // 直接在容器中构造pair
pairs.push_back(std::make_pair(2, "two")); // 构造临时对象再拷贝
cout << "emplace结果: ";
for (const auto& p : pairs) {
cout << "(" << p.first << "," << p.second << ") ";
}
cout << endl;
}
void accessElements() {
cout << "\n=== 访问元素操作 ===" << endl;
std::vector<int> vec = {10, 20, 30, 40, 50};
// 下标访问
cout << "vec[0] = " << vec[0] << endl;
cout << "vec[2] = " << vec[2] << endl;
// at()访问,带边界检查
try {
cout << "vec.at(1) = " << vec.at(1) << endl;
cout << "vec.at(10) = " << vec.at(10) << endl; // 抛出异常
} catch (const std::out_of_range& e) {
cout << "捕获异常: " << e.what() << endl;
}
// 首尾元素访问
cout << "front() = " << vec.front() << endl;
cout << "back() = " << vec.back() << endl;
// 迭代器访问
auto it = vec.begin();
cout << "*begin() = " << *it << endl;
++it;
cout << "*(++begin()) = " << *it << endl;
}
void removingElements() {
cout << "\n=== 删除元素操作 ===" << endl;
std::vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9};
cout << "原始: ";
for (auto v : vec) cout << v << " ";
cout << endl;
// pop_back - 删除尾部元素
vec.pop_back();
cout << "pop_back后: ";
for (auto v : vec) cout << v << " ";
cout << endl;
// erase - 删除指定位置元素
auto it = vec.begin() + 2;
vec.erase(it);
cout << "erase(begin+2)后: ";
for (auto v : vec) cout << v << " ";
cout << endl;
// erase - 删除范围
vec.erase(vec.begin() + 1, vec.begin() + 3);
cout << "erase范围后: ";
for (auto v : vec) cout << v << " ";
cout << endl;
// clear - 清空容器
std::list<int> lst = {10, 20, 30};
cout << "清空前list大小: " << lst.size() << endl;
lst.clear();
cout << "清空后list大小: " << lst.size() << endl;
}
int main() {
addingElements();
accessElements();
removingElements();
return 0;
}
改变容器大小
#include <iostream>
#include <vector>
#include <list>
using std::cout;
using std::endl;
void resizeOperations() {
cout << "=== 改变容器大小 ===" << endl;
// resize - 改变容器大小
std::vector<int> vec = {1, 2, 3};
cout << "初始: ";
for (auto v : vec) cout << v << " ";
cout << "大小: " << vec.size() << endl;
// 增大容器
vec.resize(5); // 新元素默认初始化
cout << "resize(5)后: ";
for (auto v : vec) cout << v << " ";
cout << "大小: " << vec.size() << endl;
// 增大容器并指定初始值
vec.resize(7, 100);
cout << "resize(7, 100)后: ";
for (auto v : vec) cout << v << " ";
cout << "大小: " << vec.size() << endl;
// 缩小容器
vec.resize(3);
cout << "resize(3)后: ";
for (auto v : vec) cout << v << " ";
cout << "大小: " << vec.size() << endl;
}
void capacityOperations() {
cout << "\n=== 容量操作 ===" << endl;
std::vector<int> vec;
cout << "初始状态:" << endl;
cout << "大小: " << vec.size() << endl;
cout << "容量: " << vec.capacity() << endl;
// 观察容量增长
for (int i = 0; i < 20; ++i) {
vec.push_back(i);
cout << "大小: " << vec.size()
<< ", 容量: " << vec.capacity() << endl;
}
// reserve - 预分配内存
std::vector<int> vec2;
vec2.reserve(100); // 预分配100个元素的空间
cout << "\nreserve(100)后:" << endl;
cout << "大小: " << vec2.size() << endl;
cout << "容量: " << vec2.capacity() << endl;
// shrink_to_fit - 请求退回多余内存(C++11)
vec.shrink_to_fit();
cout << "\nshrink_to_fit后:" << endl;
cout << "大小: " << vec.size() << endl;
cout << "容量: " << vec.capacity() << endl;
}
int main() {
resizeOperations();
capacityOperations();
return 0;
}
9.4 vector对象是如何增长的
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
void vectorGrowth() {
cout << "=== vector增长策略 ===" << endl;
std::vector<int> vec;
int previous_capacity = vec.capacity();
cout << "观察vector容量增长:" << endl;
for (int i = 0; i < 50; ++i) {
vec.push_back(i);
if (vec.capacity() != previous_capacity) {
cout << "添加元素 " << i
<< " - 大小: " << vec.size()
<< ", 新容量: " << vec.capacity()
<< ", 增长因子: " << static_cast<double>(vec.capacity()) / previous_capacity << endl;
previous_capacity = vec.capacity();
}
}
// 不同编译器的增长策略可能不同
cout << "\n典型增长策略: 1.5倍或2倍" << endl;
}
void growthStrategies() {
cout << "\n=== 容量管理策略 ===" << endl;
// 场景1:知道确切大小
cout << "场景1: 知道确切大小" << endl;
std::vector<int> vec1;
vec1.reserve(100); // 一次性分配足够空间
for (int i = 0; i < 100; ++i) {
vec1.push_back(i);
}
cout << "预分配后 - 大小: " << vec1.size()
<< ", 容量: " << vec1.capacity() << endl;
// 场景2:不知道大小,但可以估计
cout << "\n场景2: 估计大小" << endl;
std::vector<int> vec2;
vec2.reserve(50); // 估计大约需要50个元素
for (int i = 0; i < 30; ++i) { // 实际只用了30个
vec2.push_back(i);
}
vec2.shrink_to_fit(); // 释放多余内存
cout << "估计分配后 - 大小: " << vec2.size()
<< ", 容量: " << vec2.capacity() << endl;
// 场景3:完全不知道大小
cout << "\n场景3: 完全不知道大小" << endl;
std::vector<int> vec3;
for (int i = 0; i < 100; ++i) {
vec3.push_back(i); // 让vector自己管理增长
}
cout << "自动增长后 - 大小: " << vec3.size()
<< ", 容量: " << vec3.capacity() << endl;
}
int main() {
vectorGrowth();
growthStrategies();
return 0;
}
9.5 额外的string操作
#include <iostream>
#include <string>
#include <vector>
#include <cctype>
using std::cout;
using std::endl;
using std::string;
void stringConstructors() {
cout << "=== string构造函数 ===" << endl;
// 各种构造函数
string s1; // 空字符串
string s2("Hello"); // C风格字符串
string s3(s2); // 拷贝构造
string s4(5, 'A'); // 重复字符
string s5(s2, 1, 3); // 子串: "ell"
string s6("Hello World", 5); // 前5个字符: "Hello"
cout << "s1: '" << s1 << "'" << endl;
cout << "s2: '" << s2 << "'" << endl;
cout << "s3: '" << s3 << "'" << endl;
cout << "s4: '" << s4 << "'" << endl;
cout << "s5: '" << s5 << "'" << endl;
cout << "s6: '" << s6 << "'" << endl;
}
void stringOperations() {
cout << "\n=== string特殊操作 ===" << endl;
string s = "Hello World";
// 子串操作
string sub1 = s.substr(6); // "World"
string sub2 = s.substr(0, 5); // "Hello"
string sub3 = s.substr(6, 5); // "World"
cout << "s.substr(6): '" << sub1 << "'" << endl;
cout << "s.substr(0,5): '" << sub2 << "'" << endl;
cout << "s.substr(6,5): '" << sub3 << "'" << endl;
// 修改操作
s.insert(5, " Beautiful"); // "Hello Beautiful World"
s.erase(5, 10); // 删除" Beautiful"
s.replace(6, 5, "C++"); // "Hello C++"
cout << "修改后: '" << s << "'" << endl;
// 查找操作
size_t pos1 = s.find("C++");
size_t pos2 = s.find("Java");
size_t pos3 = s.find('o');
size_t pos4 = s.rfind('o'); // 从后向前找
cout << "find('C++'): " << pos1 << endl;
cout << "find('Java'): " << pos2 << " (string::npos)" << endl;
cout << "find('o'): " << pos3 << endl;
cout << "rfind('o'): " << pos4 << endl;
// 比较操作
string s1 = "apple";
string s2 = "banana";
cout << "apple compare banana: " << s1.compare(s2) << endl;
cout << "banana compare apple: " << s2.compare(s1) << endl;
}
void numericConversions() {
cout << "\n=== 数值转换 ===" << endl;
// 字符串转数值
string s1 = "42";
string s2 = "3.14159";
string s3 = "123abc";
int i = std::stoi(s1);
double d = std::stod(s2);
cout << "stoi('42') = " << i << endl;
cout << "stod('3.14159') = " << d << endl;
try {
int bad = std::stoi(s3); // 会抛出异常
} catch (const std::invalid_argument& e) {
cout << "转换错误: " << e.what() << endl;
}
// 数值转字符串
string s4 = std::to_string(123);
string s5 = std::to_string(3.14159);
cout << "to_string(123) = '" << s4 << "'" << endl;
cout << "to_string(3.14159) = '" << s5 << "'" << endl;
}
void stringAlgorithms() {
cout << "\n=== 字符串算法 ===" << endl;
string text = "Hello World, Welcome to C++ Programming!";
// 字符处理
cout << "原始: " << text << endl;
// 转换为大写
for (auto& c : text) {
c = std::toupper(c);
}
cout << "大写: " << text << endl;
// 转换为小写
for (auto& c : text) {
c = std::tolower(c);
}
cout << "小写: " << text << endl;
// 统计字符
int vowelCount = 0;
int digitCount = 0;
int spaceCount = 0;
for (char c : text) {
if (std::isalpha(c)) {
char lower = std::tolower(c);
if (lower == 'a' || lower == 'e' || lower == 'i' ||
lower == 'o' || lower == 'u') {
++vowelCount;
}
} else if (std::isdigit(c)) {
++digitCount;
} else if (std::isspace(c)) {
++spaceCount;
}
}
cout << "元音字母: " << vowelCount << endl;
cout << "数字: " << digitCount << endl;
cout << "空格: " << spaceCount << endl;
}
int main() {
stringConstructors();
stringOperations();
numericConversions();
stringAlgorithms();
return 0;
}
9.6 容器适配器
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <deque>
#include <string>
using std::cout;
using std::endl;
using std::string;
void stackDemo() {
cout << "=== stack 适配器 ===" << endl;
// stack 默认基于deque
std::stack<int> stk;
// 压栈操作
stk.push(10);
stk.push(20);
stk.push(30);
cout << "栈顶元素: " << stk.top() << endl;
cout << "栈大小: " << stk.size() << endl;
// 出栈操作
while (!stk.empty()) {
cout << "出栈: " << stk.top() << endl;
stk.pop();
}
// 基于vector的stack
// std::stack 是一个容器适配器,它基于其他容器实现栈的功能。默认情况下:
// std::stack<string> 使用 std::deque<string> 作为底层容器
// 这里显式指定使用 std::vector<string> 作为底层容器
std::stack<string, std::vector<string>> strStack;
strStack.push("first");
strStack.push("second");
strStack.push("third");
cout << "\n字符串栈:" << endl;
while (!strStack.empty()) {
cout << strStack.top() << endl;
strStack.pop();
}
}
void queueDemo() {
cout << "\n=== queue 适配器 ===" << endl;
std::queue<int> q;
// 入队操作
q.push(10);
q.push(20);
q.push(30);
cout << "队首: " << q.front() << endl;
cout << "队尾: " << q.back() << endl;
cout << "队列大小: " << q.size() << endl;
// 出队操作
while (!q.empty()) {
cout << "出队: " << q.front() << endl;
q.pop();
}
}
void priorityQueueDemo() {
cout << "\n=== priority_queue 适配器 ===" << endl;
// 最大堆(默认)
std::priority_queue<int> maxHeap;
maxHeap.push(30);
maxHeap.push(10);
maxHeap.push(50);
maxHeap.push(20);
maxHeap.push(40);
cout << "最大堆(降序输出):" << endl;
while (!maxHeap.empty()) {
cout << maxHeap.top() << " ";
maxHeap.pop();
}
cout << endl;
// 最小堆
std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;
minHeap.push(30);
minHeap.push(10);
minHeap.push(50);
minHeap.push(20);
minHeap.push(40);
cout << "最小堆(升序输出):" << endl;
while (!minHeap.empty()) {
cout << minHeap.top() << " ";
minHeap.pop();
}
cout << endl;
}
void customPriorityQueue() {
cout << "\n=== 自定义priority_queue ===" << endl;
struct Task {
string name;
int priority;
// 重载<运算符用于比较
bool operator<(const Task& other) const {
return priority < other.priority; // 数字大的优先级高
}
};
std::priority_queue<Task> taskQueue;
taskQueue.push({"低优先级任务", 1});
taskQueue.push({"高优先级任务", 3});
taskQueue.push({"中优先级任务", 2});
taskQueue.push({"紧急任务", 5});
cout << "按优先级处理任务:" << endl;
while (!taskQueue.empty()) {
Task task = taskQueue.top();
cout << "处理: " << task.name << " (优先级: " << task.priority << ")" << endl;
taskQueue.pop();
}
}
int main() {
stackDemo();
queueDemo();
priorityQueueDemo();
customPriorityQueue();
return 0;
}
综合示例:文本处理系统
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include <cctype>
using std::cout;
using std::endl;
using std::string;
using std::vector;
class TextProcessor {
private:
vector<string> lines;
public:
// 添加文本
void addLine(const string& line) {
lines.push_back(line);
}
// 显示所有文本
void display() const {
cout << "=== 文本内容 ===" << endl;
for (size_t i = 0; i < lines.size(); ++i) {
cout << i + 1 << ": " << lines[i] << endl;
}
}
// 统计信息
void showStats() const {
int totalLines = lines.size();
int totalWords = 0;
int totalChars = 0;
for (const auto& line : lines) {
totalChars += line.length();
std::istringstream iss(line);
string word;
while (iss >> word) {
++totalWords;
}
}
cout << "\n=== 统计信息 ===" << endl;
cout << "总行数: " << totalLines << endl;
cout << "总单词数: " << totalWords << endl;
cout << "总字符数: " << totalChars << endl;
}
// 搜索文本
void search(const string& keyword) const {
cout << "\n=== 搜索 '" << keyword << "' ===" << endl;
bool found = false;
for (size_t i = 0; i < lines.size(); ++i) {
if (lines[i].find(keyword) != string::npos) {
cout << "第" << i + 1 << "行: " << lines[i] << endl;
found = true;
}
}
if (!found) {
cout << "未找到包含 '" << keyword << "' 的行" << endl;
}
}
// 转换为大写
void toUpperCase() {
for (auto& line : lines) {
for (auto& c : line) {
c = std::toupper(c);
}
}
cout << "已转换为大写" << endl;
}
// 删除空行
void removeEmptyLines() {
auto newEnd = std::remove_if(lines.begin(), lines.end(),
[](const string& line) {
return line.empty() || std::all_of(line.begin(), line.end(), ::isspace);
});
lines.erase(newEnd, lines.end());
cout << "已删除空行" << endl;
}
// 获取行数
size_t getLineCount() const {
return lines.size();
}
// 获取指定行
string getLine(size_t index) const {
if (index < lines.size()) {
return lines[index];
}
return "";
}
};
int main() {
TextProcessor processor;
// 添加一些示例文本
processor.addLine("Hello World");
processor.addLine("Welcome to C++ Programming");
processor.addLine("This is a text processing example");
processor.addLine("");
processor.addLine("We are learning about containers");
processor.addLine("Vectors, strings, and algorithms");
// 显示文本
processor.display();
// 显示统计信息
processor.showStats();
// 搜索
processor.search("C++");
processor.search("vector");
// 处理文本
processor.removeEmptyLines();
processor.toUpperCase();
// 显示处理后的文本
processor.display();
return 0;
}
📝 第九章关键要点总结
-
容器选择:
vector:默认选择,随机访问高效list:频繁中间插入删除deque:频繁头尾操作array:固定大小string:字符序列专用
-
容器操作:
- 通用操作:
size(),empty(), 迭代器 - 添加元素:
push_back(),insert(),emplace() - 访问元素:
[],at(),front(),back() - 删除元素:
pop_back(),erase(),clear()
- 通用操作:
-
string特殊操作:
- 子串:
substr() - 查找:
find(),rfind() - 修改:
insert(),erase(),replace() - 数值转换:
stoi(),to_string()
- 子串:
-
容器适配器:
stack:LIFO(后进先出)queue:FIFO(先进先出)priority_queue:优先级队列
这一章的内容非常实用,顺序容器是C++编程中最常用的工具之一。多练习容器的使用,理解各种容器的特性和适用场景!
更多推荐



所有评论(0)