C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++ 常用数据结构

C++ 常用数据结构速查之vector、stack、queue、list、树、图、哈希表等声明与核心操作方法

作者:longlongzihan

本文系统梳理C++ STL中常用数据结构的声明方式与核心操作,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

C++ 常用数据结构速查,核心就一句话:‌默认优先用 vector,需要有序键值用 map,只要快速查找不要求顺序用 unordered_map,后进先出用 stack,先进先出用 queue,频繁中间增删用 list‌。‌‌

万能头文件

#include <bits/stdc++.h>
using namespace std;

bits/stdc++.h 包含了绝大多数标准库头文件,在算法竞赛和面试手撕代码时能显著节省书写时间。

注意:这是 GCC 编译器特有的非标准头文件,在 MSVC 或某些严格环境下可能无法使用,但在绝大多数在线笔试平台(牛客、LeetCode C++ 环境通常支持 GCC)中可正常工作。

一、动态数组 vector

声明:

vector<int> v;                    // 空数组
vector<int> v(10);                // 10 个 0
vector<int> v(10, 5);             // 10 个 5
vector<vector<int>> matrix(5, vector<int>(5, 0));  // 5x5 二维数组
vector<int> v = {1, 2, 3};       // 列表初始化

常用操作:

操作

代码

复杂度

尾部添加

v.push_back(x)

均摊 O(1)

尾部删除

v.pop_back()

O(1)

访问元素

v[i] 或 v.at(i)

O(1)

首尾迭代器

v.begin(), v.end()

O(1)

大小/空判断

v.size(), v.empty()

O(1)

指定位置插入

v.insert(v.begin()+i, x)

O(n)

指定位置删除

v.erase(v.begin()+i)

O(n)

调整大小

v.resize(n)

O(n)

排序

sort(v.begin(), v.end())

O(n log n)

二分查找(有序)

binary_search(v.begin(), v.end(), x)

O(log n)

常用技巧:

// 去重(需先排序)
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
// 二维数组遍历
for (auto& row : matrix) {
    for (int x : row) cout << x << " ";
}

二、栈 stack

声明:

stack<int> s;

常用操作:

操作

代码

入栈

s.push(x)

出栈

s.pop()(无返回值)

取栈顶

s.top()

判空

s.empty()

大小

s.size()

栈适用于括号匹配、逆波兰表达式求值、单调栈等场景。底层默认使用 deque,但是相对来说算是细节,一般不需要关心 。

三、队列 queue

声明:

queue<int> q;

常用操作:

操作

代码

入队

q.push(x)

出队

q.pop()(无返回值)

取队首

q.front()

取队尾

q.back()

判空/大小

q.empty(), q.size()

BFS 的标配容器。如果需要双端操作,使用 deque:

deque<int> dq;
dq.push_back(x);   // 尾插
dq.push_front(x);  // 头插 O(1)
dq.pop_back();
dq.pop_front();

四、优先队列 priority_queue

声明:

priority_queue<int> pq;                                    // 大顶堆(默认)
priority_queue<int, vector<int>, greater<int>> min_pq;     // 小顶堆

常用操作:

操作

代码

插入

pq.push(x)

删除堆顶

pq.pop()

取堆顶

pq.top()

判空/大小

pq.empty(), pq.size()

自定义类型:

struct Node { int dist; int id; };
struct cmp {
    bool operator()(Node& a, Node& b) {
        return a.dist > b.dist;  // 距离小的优先级高(小顶堆)
    }
};
priority_queue<Node, vector<Node>, cmp> pq;

适用于 Dijkstra、Top K 问题、任务调度等 。

五、链表 list

声明:

list<int> lst;

常用操作:

操作

代码

头/尾插入

lst.push_front(x), lst.push_back(x)

头/尾删除

lst.pop_front(), lst.pop_back()

指定位置插入

lst.insert(it, x)

删除元素

lst.erase(it)

排序

lst.sort()

判空/大小

lst.empty(), lst.size()

list 是双向链表,不支持随机访问 []。插入删除 O(1)(已知迭代器位置),但查找 O(n) 。

手撕链表通常需要手写节点结构,因为面试官考察的是指针操作:

struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
};

六、树(set / map:平衡二叉搜索树)

STL 没有直接提供“树”容器,但 set 和 map 底层是红黑树(平衡 BST),提供 O(log n) 的有序操作。

set(有序集合,去重)

声明:

set<int> s;

常用操作:

s.insert(x);           // 插入 O(log n)
s.erase(x);            // 删除
s.find(x);             // 查找,返回迭代器
s.count(x);            // 存在返回 1
s.lower_bound(x);      // >= x 的第一个元素
s.upper_bound(x);      // > x 的第一个元素

map(有序键值对)

声明:

map<string, int> mp;

常用操作:

mp["key"] = 1;              // 插入/修改
mp.insert({"key", 1});
mp.erase("key");
mp.find("key");             // 返回迭代器
mp.count("key");            // 判断存在
for (auto& [k, v] : mp)     // C++17 结构化绑定遍历
    cout << k << ": " << v;

手写二叉树节点

struct TreeNode {
    int val;
    TreeNode *left, *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

七、哈希表 unordered_map / unordered_set

声明:

unordered_map<int, int> hashmap;    // 键值对
unordered_set<int> hashset;         // 集合

常用操作(与 map/set 类似,但无序):

操作

代码

平均复杂度

插入/修改

mp[key] = val

O(1)

查找

mp.find(key)

O(1)

存在判断

mp.count(key)

O(1)

删除

mp.erase(key)

O(1)

关键区别:

unordered_map 平均 O(1),但最坏 O(n)(哈希冲突),且无序

map 稳定 O(log n),有序,可用 lower_bound

面试中涉及“查找/计数/去重”且不要求顺序时,优先使用 unordered_map 或 unordered_set 。

八、图(邻接表表示)

C++ STL 没有内置图容器,通常用 vector 模拟邻接表:

// 邻接表:g[u] 存储 u 的所有邻居
vector<vector<int>> g(n + 1);
// 添加有向边 u -> v
g[u].push_back(v);
// 添加无向边
g[u].push_back(v);
g[v].push_back(u);
// 带权图:pair<邻点, 权重>
vector<vector<pair<int, int>>> wg(n + 1);
wg[u].push_back({v, w});

BFS 遍历模板:

queue<int> q;
vector<bool> visited(n + 1, false);
q.push(start);
visited[start] = true;
while (!q.empty()) {
    int u = q.front(); q.pop();
    for (int v : g[u]) {
        if (!visited[v]) {
            visited[v] = true;
            q.push(v);
        }
    }
}

DFS 递归模板:

void dfs(int u, vector<vector<int>>& g, vector<bool>& visited) {
    visited[u] = true;
    for (int v : g[u]) {
        if (!visited[v]) dfs(v, g, visited);
    }
}

九、C++17 结构化绑定(强烈推荐)

在遍历 map 或 vector<pair> 时,结构化绑定可以大幅简化代码:

// 以前
for (auto& it : mp) {
    cout << it.first << " " << it.second;
}
// C++17
for (auto& [key, value] : mp) {
    cout << key << " " << value;
}

配合 auto&& 使用可以避免不必要的拷贝。

到此这篇关于C++ 常用数据结构速查之vector、stack、queue、list、树、图、哈希表等声明与核心操作方法的文章就介绍到这了,更多相关C++ 常用数据结构内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文