Files
handsomezhuzhu.github.io/docs/sop/notes/acm-cpp-cheatsheet.md
2026-01-16 01:09:48 +08:00

399 lines
9.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: 数据结构与算法实验(C++)
date: 2026-01-15
descriptionHTML: '<span style="color:var(--description-font-color);">整理了数据结构考试中常用的C++模板与算法讲解</span>'
tags:
- 笔记
- C++
- 算法
sidebar: true
readingTime: true
hidden: false
recommend: true
---
# 数据结构与算法实验(C++)
这份笔记整理了数据结构考试中常用的C++模板与算法讲解
## 1. 基础环境 (Template)
```cpp
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <stack>
#include <queue>
#include <functional> // for greater
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
int main() {
// 核心关闭同步加速cin/cout
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
// 在这里写你的代码
return 0;
}
```
---
## 2. 基础数据结构与 STL
### 2.1 指针与引用 (Pointers & References)
**这是很多同学容易混淆的地方,尤其是在函数传参时。**
#### 1. 如何定义
```cpp
int a = 10;
int* p = &a; // p 是指针,存储 a 的地址
int& r = a; // r 是引用r 就是 a 的别名 (即 r 和 a 是同一个东西)
```
#### 2. 函数传参:值传递 vs 引用传递 vs 指针传递
**场景**:你需要在一个函数里修改外面的变量,或者传递大数组不希望发生拷贝。
**A. 引用传递 (`Type& name`) —— 最推荐**
如果函数参数里写了 `&`,你在函数里**直接把它当成普通变量用**就行。
```cpp
// 这里的 x 就是外面传进来的那个变量的“分身”
void modify(int& x) {
x = 100; // 不需要加 *,直接修改
}
int main() {
int num = 0;
modify(num); // num 变成 100
}
```
**B. 指针传递 (`Type* name`)**
需要传地址,函数里要用 `*` 解引用。
```cpp
void modifyPtr(int* p) {
if (p == NULL) return;
*p = 100; // *p 代表指针指向的那个变量
}
int main() {
int num = 0;
modifyPtr(&num); // 注意:要取地址符 &
}
```
**总结**
* 看到 `void func(int &x)` -> 内部直接用 `x`,改变会影响外面。
* 看到 `void func(int *x)` -> 内部用 `*x` 访问值,调用时传地址 `&a`
* 链表/树结构通常用指针 (`ListNode*`),因为可能为空 (`NULL`)。
### 2.2 常用 STL 容器
**Stack (栈)**: 先进后出 (LIFO)用于括号匹配、DFS。
```cpp
stack<int> s;
s.push(1); s.pop(); s.top(); s.empty();
```
**Queue (队列)**: 先进先出 (FIFO)用于BFS、层序遍历。
```cpp
queue<int> q;
q.push(1); q.pop(); q.front(); q.empty();
```
**Vector (动态数组)**:
```cpp
vector<int> v;
v.push_back(1);
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end()); // 排序后去重
```
**Priority Queue (优先队列)**: 默认大根堆。
```cpp
priority_queue<int> pq; // 大根堆
priority_queue<int, vector<int>, greater<int>> min_pq; // 小根堆
```
### 2.2 单链表 (Linked List)
**技巧**: 使用虚拟头结点 (dummy head) 处理删除操作。
```cpp
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
// 1. 尾插法创建
ListNode* createList(const vector<int>& nums) {
ListNode* dummy = new ListNode(0);
ListNode* tail = dummy;
for (int x : nums) {
tail->next = new ListNode(x);
tail = tail->next;
}
return dummy->next;
}
// 2. 反转链表
ListNode* reverseList(ListNode* head) {
ListNode *prev = NULL, *curr = head;
while (curr) {
ListNode* nextTemp = curr->next;
curr->next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}
// 3. 删除指定值的节点
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* cur = dummy;
while (cur->next) {
if (cur->next->val == val) {
ListNode* temp = cur->next;
cur->next = cur->next->next;
delete temp;
} else {
cur = cur->next;
}
}
return dummy->next;
}
```
---
## 3. 基础算法
### 3.1 二分查找 (Binary Search)
**适用**: 有序数组中查找。
```cpp
// 查找第一个 >= target 的位置
int lower_bound_custom(const vector<int>& arr, int target) {
int l = 0, r = arr.size() - 1, ans = -1;
while (l <= r) {
int mid = l + (r - l) / 2;
if (arr[mid] >= target) {
ans = mid;
r = mid - 1;
} else {
l = mid + 1;
}
}
return ans;
}
```
### 3.2 快速幂 (Quick Power)
**功能**: 计算 $a^b \pmod m$。
```cpp
ll qpow(ll a, ll b, ll m) {
ll res = 1;
a %= m;
while (b) {
if (b & 1) res = (res * a) % m;
a = (a * a) % m;
b >>= 1;
}
return res;
}
```
---
## 4. 字符串算法
### KMP 算法
**功能**: 字符串匹配,求 pattern 在 text 中的位置。
```cpp
// 求 next 数组
vector<int> getNext(string p) {
int m = p.size(), j = 0;
vector<int> nxt(m);
nxt[0] = 0;
for (int i = 1; i < m; i++) {
while (j > 0 && p[i] != p[j]) j = nxt[j - 1];
if (p[i] == p[j]) j++;
nxt[i] = j;
}
return nxt;
}
// KMP 匹配
int kmp(string text, string pattern) {
if (pattern.empty()) return 0;
vector<int> nxt = getNext(pattern);
int j = 0;
for (int i = 0; i < text.size(); i++) {
while (j > 0 && text[i] != pattern[j]) j = nxt[j - 1];
if (text[i] == pattern[j]) j++;
if (j == pattern.size()) return i - pattern.size() + 1;
}
return -1;
}
```
---
## 5. 树 (Tree)
### 5.1 二叉树遍历
```cpp
struct TreeNode {
int val;
TreeNode *left, *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
// 递归遍历 (Pre/In/Post)
void dfs(TreeNode* root) {
if (!root) return;
// cout << root->val; // 先序
dfs(root->left);
// cout << root->val; // 中序
dfs(root->right);
// cout << root->val; // 后序
}
// 层序遍历 (BFS)
void levelOrder(TreeNode* root) {
if (!root) return;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
TreeNode* node = q.front(); q.pop();
cout << node->val << " ";
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
}
```
### 5.2 并查集 (Union-Find)
**功能**: 集合合并与查询。
```cpp
int fa[10005];
void init(int n) { for(int i=1; i<=n; i++) fa[i]=i; }
int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } // 路径压缩
void unite(int x, int y) { fa[find(x)] = find(y); }
```
### 5.3 树状数组 (Fenwick Tree)
**功能**: 单点修改,区间查询前缀和。
```cpp
int bit[10005], n;
int lowbit(int x) { return x & -x; }
void add(int x, int k) { for(; x<=n; x+=lowbit(x)) bit[x]+=k; }
int query(int x) { int s=0; for(; x>0; x-=lowbit(x)) s+=bit[x]; return s; }
```
---
## 6. 图论 (Graph)
### 6.1 存图与遍历 (Adjacency List, DFS, BFS)
```cpp
struct edge { int to, w; };
vector<vector<edge>> adj; // adj[u] 存 u 的出边
vector<bool> vis;
// DFS
void dfs(int u) {
vis[u] = true;
for (auto e : adj[u]) {
if (!vis[e.to]) dfs(e.to);
}
}
// BFS (求无权图最短路)
void bfs(int s) {
queue<int> q; q.push(s); vis[s] = true;
while (!q.empty()) {
int u = q.front(); q.pop();
for (auto e : adj[u]) {
if (!vis[e.to]) {
vis[e.to] = true;
q.push(e.to);
}
}
}
}
```
### 6.2 最短路 Dijkstra (堆优化)
**注意**: 仅适用于非负权边。
```cpp
vector<int> dis;
void dijkstra(int s, int n) {
dis.assign(n + 1, INF);
dis[s] = 0;
priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;
pq.push({0, s});
while (!pq.empty()) {
int d = pq.top().first;
int u = pq.top().second;
pq.pop();
if (d > dis[u]) continue;
for (auto e : adj[u]) {
if (dis[u] + e.w < dis[e.to]) {
dis[e.to] = dis[u] + e.w;
pq.push({dis[e.to], e.to});
}
}
}
}
```
### 6.3 最小生成树 (Kruskal)
**原理**: 贪心,按边权从小到大选边,并查集判环。
```cpp
struct Edge {
int u, v, w;
bool operator<(const Edge& o) const { return w < o.w; }
} edges[20005];
int kruskal(int n, int m) {
sort(edges, edges + m);
init(n); // 并查集初始化
int res = 0, cnt = 0;
for (int i = 0; i < m; i++) {
if (find(edges[i].u) != find(edges[i].v)) {
unite(edges[i].u, edges[i].v);
res += edges[i].w;
cnt++;
}
}
return cnt == n - 1 ? res : -1;
}
```
### 6.4 拓扑排序 (Topological Sort)
**功能**: 有向无环图 (DAG) 的排序。
```cpp
int in_degree[10005]; // 需预处理入度
vector<int> toposort(int n) {
queue<int> q;
for(int i=1; i<=n; i++) if(in_degree[i]==0) q.push(i);
vector<int> res;
while(!q.empty()){
int u = q.front(); q.pop();
res.push_back(u);
for(auto e : adj[u]){
if(--in_degree[e.to] == 0) q.push(e.to);
}
}
return res;
}
```