C++ 是一种功能强大且灵活的编程语言,提供了多种数据结构来有效地组织和管理数据。掌握这些数据结构对于写出高效、可维护的代码至关重要。本文将详细讨论 C++ 中常见的数据结构,包括数组、链表、栈、队列、树、图以及 C++ STL 中提供的容器,例如向量(vector
)、列表(list
)、集合(set
)、映射(map
)、哈希表(unordered_map
)、智能指针等。
一、基本数据结构
1. 数组(Array)
数组是存储相同类型元素的固定大小的集合。数组是最基本的数据结构之一,支持随机访问。
#include <iostream>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
for (int i = 0; i < 5; ++i) {
std::cout << arr[i] << " "; // 输出:10 20 30 40 50
}
return 0;
}
优缺点:
- 优点:快速的随机访问(O(1)),内存开销小。
- 缺点:固定大小,不方便插入和删除。
2. 链表(Linked List)
链表是由节点组成的线性数据结构,每个节点包含数据和指向下一个节点的指针。链表有单向链表和双向链表之分。
#include <iostream>
struct Node {
int data;
Node* next;
};
void printList(Node* head) {
Node* temp = head;
while (temp) {
std::cout << temp->data << " "; // 输出链表节点的数据
temp = temp->next;
}
}
int main() {
Node* head = new Node{10, nullptr};
head->next = new Node{20, nullptr};
head->next->next = new Node{30, nullptr};
printList(head); // 输出:10 20 30
// 释放内存(未实现)
return 0;
}
优缺点:
- 优点:动态大小,方便插入和删除(O(1))。
- 缺点:随机访问速度慢(O(n)),额外的内存开销用于存储指针。
3. 栈(Stack)
栈是一个后进先出(LIFO,Last In First Out)数据结构。可以使用数组或链表实现。
#include <iostream>
#include <stack>
int main() {
std::stack<int> s;
s.push(1);
s.push(2);
s.push(3);
while (!s.empty()) {
std::cout << s.top() << " "; // 输出:3 2 1
s.pop();
}
return 0;
}
优缺点:
- 优点:操作简单,适用于临时存储数据,快速(O(1))。
- 缺点:只能访问栈顶元素,不支持随机访问。
4. 队列(Queue)
队列是一个先进先出(FIFO,First In First Out)数据结构。可以使用数组或链表实现。
#include <iostream>
#include <queue>
int main() {
std::queue<int> q;
q.push(1);
q.push(2);
q.push(3);
while (!q.empty()) {
std::cout << q.front() << " "; // 输出:1 2 3
q.pop();
}
return 0;
}
优缺点:
- 优点:适合处理顺序性的数据。
- 缺点:同样不允许随机访问。
二、树(Tree)
1. 二叉树(Binary Tree)
每个节点最多有两个子节点的树结构。常用于实现搜索树、堆等数据结构。
#include <iostream>
struct Node {
int data;
Node* left;
Node* right;
};
void inorderTraversal(Node* root) {
if (root) {
inorderTraversal(root->left);
std::cout << root->data << " "; // 中序遍历
inorderTraversal(root->right);
}
}
int main() {
Node* root = new Node{1, nullptr, nullptr};
root->left = new Node{2, nullptr, nullptr};
root->right = new Node{3, nullptr, nullptr};
inorderTraversal(root); // 输出:2 1 3
// 释放内存(未实现)
return 0;
}
2. 二叉搜索树(Binary Search Tree)
满足左子树小于根节点,右子树大于根节点的二叉树,用于高效的查找操作。
#include <iostream>
struct Node {
int data;
Node* left;
Node* right;
Node(int value) : data(value), left(nullptr), right(nullptr) {}
};
Node* insert(Node* root, int value) {
if (!root) return new Node(value);
if (value < root->data)
root->left = insert(root->left, value);
else
root->right = insert(root->right, value);
return root;
}
void inorderTraversal(Node* root) {
if (root) {
inorderTraversal(root->left);
std::cout << root->data << " ";
inorderTraversal(root->right);
}
}
int main() {
Node* root = nullptr;
root = insert(root, 3);
insert(root, 1);
insert(root, 2);
insert(root, 4);
inorderTraversal(root); // 输出:1 2 3 4
return 0;
}
三、图(Graph)
图是一种非线性数据结构,包含节点和连接节点的边。图有有向图和无向图之分。
#include <iostream>
#include <vector>
class Graph {
int V; // 节点数
std::vector<std::vector<int>> adj; // 邻接表
public:
Graph(int v) : V(v), adj(v) {}
void addEdge(int u, int v) {
adj[u].push_back(v); // 有向图,将 v 添加到 u 的邻接表
}
void printGraph() {
for (int i = 0; i < V; ++i) {
std::cout << i << ": ";
for (int j : adj[i]) {
std::cout << j << " ";
}
std::cout << std::endl;
}
}
};
int main() {
Graph g(5);
g.addEdge(0, 1);
g.addEdge(0, 4);
g.addEdge(1, 2);
g.addEdge(1, 3);
g.addEdge(1, 4);
g.addEdge(2, 3);
g.addEdge(3, 4);
g.printGraph();
return 0;
}
四、C++ STL 中的容器
C++ 标准库 STL (Standard Template Library) 提供了多个容器类,使得数据结构的实现和管理更为简便。以下是常用的 STL 容器:
1. 向量(std::vector
)
动态数组,支持快速随机访问和动态扩展。
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
vec.push_back(6); // 添加元素
for (int i : vec) {
std::cout << i << " "; // 输出:1 2 3 4 5 6
}
return 0;
}
2. 列表(std::list
)
双向链表的实现,支持快速插入和删除操作,但不支持随机访问。
#include <iostream>
#include <list>
int main() {
std::list<int> lst = {1, 2, 3};
lst.push_back(4);
lst.push_front(0);
for (int i : lst) {
std::cout << i << " "; // 输出:0 1 2 3 4
}
return 0;
}
3. 集合(std::set
)
按顺序存储唯一元素的集合,基于红黑树实现。
#include <iostream>
#include <set>
int main() {
std::set<int> s = {1, 2, 3};
s.insert(2); // 不会插入第二个 2
s.insert(4);
for (int i : s) {
std::cout << i << " "; // 输出:1 2 3 4
}
return 0;
}
4. 映射(std::map
)
基于键值对存储的有序容器,适合快速查找和删除。
#include <iostream>
#include <map>
int main() {
std::map<std::string, int> m;
m["apple"] = 1;
m["banana"] = 2;
m["orange"] = 3;
for (const auto& pair : m) {
std::cout << pair.first << ": " << pair.second << std::endl; // 输出键值对
}
return 0;
}
5. 哈希表(std::unordered_map
)
基于哈希表实现的,无序容器,支持快速的键值对存取操作。
#include <iostream>
#include <unordered_map>
int main() {
std::unordered_map<std::string, int> umap;
umap["apple"] = 1;
umap["banana"] = 2;
for (const auto& pair : umap) {
std::cout << pair.first << ": " << pair.second << std::endl; // 输出键值对
}
return 0;
}
五、智能指针
智能指针是 C++11 引入的一种管理动态内存的方法,减少内存泄漏的风险。常见的智能指针有 std::unique_ptr
和 std::shared_ptr
。
#include <iostream>
#include <memory>
int main() {
std::unique_ptr<int> uptr(new int(10)); // 创建 unique_ptr
std::cout << *uptr << std::endl; // 输出:10
// std::shared_ptr<int> sptr = std::make_shared<int>(20); // 创建 shared_ptr
// std::cout << *sptr << std::endl; // 输出:20
return 0;
}