NewCodeTemplate

This commit is contained in:
e2hang
2025-12-16 20:36:27 +08:00
parent 684e35b210
commit 8253f2dcbc
26 changed files with 2547 additions and 0 deletions

76
模板/树/Huffman.cpp Normal file
View File

@@ -0,0 +1,76 @@
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
/*
Huffman 树节点
在竞赛中一般不需要真的建树,只关心权值
*/
struct Node {
long long w; // 当前节点权值
Node(long long _w) : w(_w) {}
};
/*
priority_queue 默认是大根堆
这里通过重载比较函数,使其变为小根堆
*/
struct cmp {
bool operator()(const Node& a, const Node& b) const {
return a.w > b.w; // 权值小的优先
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
/*
优先队列(小根堆)
每次可以 O(log n) 取出最小的两个权值
*/
priority_queue<Node, vector<Node>, cmp> pq;
// 读入 n 个权值
for (int i = 0; i < n; i++) {
long long x;
cin >> x;
pq.push(Node(x));
}
/*
特判:只有一个节点
WPL = 0没有边
*/
if (n == 1) {
cout << 0 << '\n';
return 0;
}
long long WPL = 0;
/*
Huffman 树构造过程
每次取最小的两个合并
*/
while (pq.size() > 1) {
Node a = pq.top(); pq.pop();
Node b = pq.top(); pq.pop();
long long mergedWeight = a.w + b.w;
WPL += mergedWeight;
pq.push(Node(mergedWeight));
}
// 输出带权路径长度
cout << WPL << '\n';
return 0;
}

View File

@@ -0,0 +1,24 @@
#include <iostream>
#include <queue>
using namespace std;
int main(){
priority_queue<int, vector<int>, greater<int>> pq;
int n;
cin >> n;
int tmp;
int sum = 0;
for(int i = 0; i < n; i++){
cin >> tmp;
sum += tmp;
pq.push(tmp);
}
long long ans = 0;
while(pq.size() > 1){
int x = pq.top(); pq.pop();
int y = pq.top(); pq.pop();
pq.push(x + y);
ans += (x + y);
}
cout << ans << endl;
return 0;
}

View File

@@ -0,0 +1,51 @@
#include <iostream>
#include <vector>
using namespace std;
struct TreeNode{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int _val): val(_val), left(nullptr), right(nullptr) {}
};
TreeNode* buildTree(const vector<int>& arr, int& idx){
if(arr.empty()) return nullptr;
if(idx >= arr.size() || arr[idx] == 0){
idx++;
return nullptr;
}
TreeNode* node = new TreeNode(arr[idx++]);
node->left = buildTree(arr, idx);
node->right = buildTree(arr, idx);
return node;
}
TreeNode* LCA = nullptr;
TreeNode* check(TreeNode* root, int val1, int val2){
if(root == nullptr) return nullptr;
if(root->val == val1 || root->val == val2) return root;
TreeNode* lc = check(root->left, val1, val2);
TreeNode* rc = check(root->right, val1, val2);
if(lc && rc) return root;
return (lc ? lc : rc);
}
int main(){
//前序增强输入
int n;
cin >> n;
vector<int> arr(n);
for(int i = 0; i < n; i++){
cin >> arr[i];
}
int pa, pb;
cin >> pa >> pb;
int p = 0;
TreeNode* root = buildTree(arr, p);
LCA = check(root, pa, pb);
cout << LCA->val << endl;
return 0;
}

View File

@@ -0,0 +1,186 @@
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
/*====================================================
= 二叉树节点定义 =
====================================================*/
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
/*====================================================
= 前序 + 中序 重建二叉树(模块一) =
====================================================*/
class BuildFromPreIn {
public:
unordered_map<int, int> pos; // 中序遍历中:值 -> 下标
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int n = preorder.size();
pos.clear();
for (int i = 0; i < n; i++) {
pos[inorder[i]] = i;
}
return dfs(preorder, 0, n - 1, inorder, 0, n - 1);
}
private:
TreeNode* dfs(vector<int>& pre, int preL, int preR,
vector<int>& in, int inL, int inR) {
if (preL > preR) return nullptr;
// 前序第一个元素是当前子树的根
int rootVal = pre[preL];
TreeNode* root = new TreeNode(rootVal);
// 根在中序中的位置
int k = pos[rootVal];
int leftSize = k - inL;
// 构建左子树
root->left = dfs(
pre,
preL + 1,
preL + leftSize,
in,
inL,
k - 1
);
// 构建右子树
root->right = dfs(
pre,
preL + leftSize + 1,
preR,
in,
k + 1,
inR
);
return root;
}
};
/*====================================================
= 中序 + 后序 重建二叉树(模块二) =
====================================================*/
class BuildFromInPost {
public:
unordered_map<int, int> pos; // 中序遍历中:值 -> 下标
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
int n = inorder.size();
pos.clear();
for (int i = 0; i < n; i++) {
pos[inorder[i]] = i;
}
return dfs(inorder, 0, n - 1, postorder, 0, n - 1);
}
private:
TreeNode* dfs(vector<int>& in, int inL, int inR,
vector<int>& post,int postL, int postR) {
if (inL > inR) return nullptr;
// 后序最后一个元素是当前子树的根
int rootVal = post[postR];
TreeNode* root = new TreeNode(rootVal);
// 根在中序中的位置
int k = pos[rootVal];
int leftSize = k - inL;
// 构建左子树
root->left = dfs(
in,
inL,
k - 1,
post,
postL,
postL + leftSize - 1
);
// 构建右子树
root->right = dfs(
in,
k + 1,
inR,
post,
postL + leftSize,
postR - 1
);
return root;
}
};
/*====================================================
= 辅助函数:遍历与验证 =
====================================================*/
// 中序遍历(用于验证结构是否正确)
void inorderPrint(TreeNode* root) {
if (!root) return;
inorderPrint(root->left);
cout << root->val << ' ';
inorderPrint(root->right);
}
// 后序遍历
void postorderPrint(TreeNode* root) {
if (!root) return;
postorderPrint(root->left);
postorderPrint(root->right);
cout << root->val << ' ';
}
// 前序遍历
void preorderPrint(TreeNode* root) {
if (!root) return;
cout << root->val << ' ';
preorderPrint(root->left);
preorderPrint(root->right);
}
/*====================================================
= main =
====================================================*/
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
/*
示例测试数据
前序: 3 9 20 15 7
中序: 9 3 15 20 7
后序: 9 15 7 20 3
*/
vector<int> preorder = {3, 9, 20, 15, 7};
vector<int> inorder = {9, 3, 15, 20, 7};
vector<int> postorder = {9, 15, 7, 20, 3};
// 前序 + 中序
BuildFromPreIn solver1;
TreeNode* root1 = solver1.buildTree(preorder, inorder);
// 中序 + 后序
BuildFromInPost solver2;
TreeNode* root2 = solver2.buildTree(inorder, postorder);
// 验证输出
inorderPrint(root1);
cout << '\n';
inorderPrint(root2);
cout << '\n';
return 0;
}

View File

@@ -0,0 +1,35 @@
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void dfs(TreeNode* root, vector<int>& path, int sum, int target){
if(root == nullptr) return;
path.push_back(root->val);
sum += root->val;
if(sum == target && root->left == nullptr && root->right == nullptr){
result.push_back(path);
}
dfs(root->left, path, sum, target);
dfs(root->right, path, sum, target);
path.pop_back();
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
dfs(root, path, 0, targetSum);
return result;
}
};

View File

@@ -0,0 +1,209 @@
#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <sstream>
#include <unordered_set>
#include <algorithm>
using namespace std;
/* ======================= 节点定义 ======================= */
struct TreeNode {
string val;
TreeNode* left;
TreeNode* right;
TreeNode* parent;
TreeNode(const string& v)
: val(v), left(nullptr), right(nullptr), parent(nullptr) {}
};
/* ======================= 建树(增强前序) =======================
输入示例:
A B D # # E # # C # #
*/
TreeNode* buildTree(queue<string>& tokens, TreeNode* parent = nullptr) {
if (tokens.empty()) return nullptr;
string cur = tokens.front();
tokens.pop();
if (cur == "#") return nullptr;
TreeNode* node = new TreeNode(cur);
node->parent = parent;
node->left = buildTree(tokens, node);
node->right = buildTree(tokens, node);
return node;
}
/* ======================= DFS前序 ======================= */
void preorder(TreeNode* root) {
if (!root) return;
cout << root->val << " ";
preorder(root->left);
preorder(root->right);
}
/* ======================= BFS层序 ======================= */
void bfs(TreeNode* root) {
if (!root) return;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
TreeNode* cur = q.front();
q.pop();
cout << cur->val << " ";
if (cur->left) q.push(cur->left);
if (cur->right) q.push(cur->right);
}
}
/* ======================= 查找节点DFS ======================= */
TreeNode* findNode(TreeNode* root, const string& target) {
if (!root) return nullptr;
if (root->val == target) return root;
TreeNode* leftRes = findNode(root->left, target);
if (leftRes) return leftRes;
return findNode(root->right, target);
}
/* ======================= 树高度 =======================
空树高度 = -1
单节点高度 = 0
*/
int height(TreeNode* root) {
if (!root) return -1;
return max(height(root->left), height(root->right)) + 1;
}
/* ======================= 添加节点 ======================= */
bool addNode(TreeNode* root, const string& parentVal,
const string& newVal, bool isLeft) {
if (!root) return false;
if (root->val == parentVal) {
if (isLeft && !root->left) {
root->left = new TreeNode(newVal);
root->left->parent = root;
return true;
}
if (!isLeft && !root->right) {
root->right = new TreeNode(newVal);
root->right->parent = root;
return true;
}
return false;
}
return addNode(root->left, parentVal, newVal, isLeft) ||
addNode(root->right, parentVal, newVal, isLeft);
}
/* ======================= 删除整棵子树 ======================= */
void deleteSubtree(TreeNode* node) {
if (!node) return;
deleteSubtree(node->left);
deleteSubtree(node->right);
if (node->parent) {
if (node->parent->left == node)
node->parent->left = nullptr;
else if (node->parent->right == node)
node->parent->right = nullptr;
}
delete node;
}
/* ======================= 删除单个节点 ======================= */
void deleteNode(TreeNode* node) {
if (!node) return;
// 叶子节点
if (!node->left && !node->right) {
if (node->parent) {
if (node->parent->left == node)
node->parent->left = nullptr;
else
node->parent->right = nullptr;
}
delete node;
return;
}
// 只有一个孩子
if (!node->left || !node->right) {
TreeNode* child = node->left ? node->left : node->right;
child->parent = node->parent;
if (node->parent) {
if (node->parent->left == node)
node->parent->left = child;
else
node->parent->right = child;
}
delete node;
return;
}
// 两个孩子:中序后继替换
TreeNode* succ = node->right;
while (succ->left) succ = succ->left;
node->val = succ->val;
deleteNode(succ);
}
/* ======================= LCA父指针法 ======================= */
TreeNode* lca_parent(TreeNode* a, TreeNode* b) {
unordered_set<TreeNode*> vis;
while (a) {
vis.insert(a);
a = a->parent;
}
while (b) {
if (vis.count(b)) return b;
b = b->parent;
}
return nullptr;
}
/* ======================= 示例主函数 ======================= */
int main() {
/*
输入示例(第一行用于建树):
A B D # # E # # C # #
*/
string line;
getline(cin, line);
stringstream ss(line);
queue<string> tokens;
string tok;
while (ss >> tok) tokens.push(tok);
TreeNode* root = buildTree(tokens);
cout << "DFS (preorder): ";
preorder(root);
cout << "\n";
cout << "BFS: ";
bfs(root);
cout << "\n";
cout << "Tree height: " << height(root) << "\n";
TreeNode* x = findNode(root, "D");
TreeNode* y = findNode(root, "E");
if (x && y) {
TreeNode* lca = lca_parent(x, y);
if (lca)
cout << "LCA of D and E: " << lca->val << "\n";
}
deleteSubtree(root);
return 0;
}

94
模板/树/并查集.cpp Normal file
View File

@@ -0,0 +1,94 @@
#include <iostream>
#include <vector>
using namespace std;
/*
并查集Disjoint Set Union
支持:
- 路径压缩
- 按集合大小合并
*/
struct DSU {
vector<int> parent; // parent[x]x 的父节点
vector<int> sz; // sz[x]:以 x 为根的集合大小
int components; // 当前连通分量个数(可选)
// 构造函数:初始化 n 个元素(编号 0 ~ n-1
DSU(int n = 0) {
init(n);
}
// 初始化
void init(int n) {
parent.resize(n);
sz.assign(n, 1);
components = n;
for (int i = 0; i < n; i++) {
parent[i] = i; // 初始时,每个节点都是自己的父节点
}
}
// 查找 x 的根(带路径压缩)
int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]); // 路径压缩
}
return parent[x];
}
// 合并 x 和 y 所在的集合
// 如果本来就在同一集合,返回 false
bool unite(int x, int y) {
int rx = find(x);
int ry = find(y);
if (rx == ry) return false;
// 按集合大小合并:小的挂到大的
if (sz[rx] < sz[ry]) {
swap(rx, ry);
}
parent[ry] = rx;
sz[rx] += sz[ry];
components--; // 连通分量减少
return true;
}
// 判断 x 和 y 是否在同一集合
bool same(int x, int y) {
return find(x) == find(y);
}
// 返回 x 所在集合的大小
int size(int x) {
return sz[find(x)];
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
DSU dsu(n);
/*
示例:
m 次操作,每次合并两个点
*/
for (int i = 0; i < m; i++) {
int a, b;
cin >> a >> b;
dsu.unite(a, b);
}
cout << dsu.components << '\n';
return 0;
}

166
模板/树/树的直径.cpp Normal file
View File

@@ -0,0 +1,166 @@
#include <iostream>
#include <vector>
#include <queue>
#include <unordered_map>
#include <algorithm>
using namespace std;
/*====================================================
= 二叉树节点定义 =
====================================================*/
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
/*====================================================
= 方法一:使用 parent 指针 + BFS 求树的直径 =
= 思路Tree -> 无向图 -> 两次 BFS =
====================================================*/
/*
建立 parent 映射 + 邻接表
把“只有 left/right 的树”变成“无向图”
*/
void buildGraph(
TreeNode* root,
TreeNode* parent,
unordered_map<TreeNode*, vector<TreeNode*>>& adj
) {
if (!root) return;
if (parent) {
adj[root].push_back(parent);
adj[parent].push_back(root);
}
buildGraph(root->left, root, adj);
buildGraph(root->right, root, adj);
}
/*
从 start 出发 BFS返回
- 距离最远的节点
- 以及对应的距离
*/
pair<TreeNode*, int> bfs(
TreeNode* start,
unordered_map<TreeNode*, vector<TreeNode*>>& adj
) {
queue<TreeNode*> q;
unordered_map<TreeNode*, int> dist;
q.push(start);
dist[start] = 0;
TreeNode* far = start;
while (!q.empty()) {
TreeNode* u = q.front();
q.pop();
far = u;
for (TreeNode* v : adj[u]) {
if (!dist.count(v)) {
dist[v] = dist[u] + 1;
q.push(v);
}
}
}
return {far, dist[far]};
}
/*
使用 parent 思路求直径
*/
int diameterWithParent(TreeNode* root) {
if (!root) return 0;
unordered_map<TreeNode*, vector<TreeNode*>> adj;
// 建图(隐式利用 parent
buildGraph(root, nullptr, adj);
// 第一次 BFS随便找一个最远点 A
auto [A, _] = bfs(root, adj);
// 第二次 BFS从 A 出发,找到最远点 B
auto [B, diameter] = bfs(A, adj);
return diameter;
}
/*====================================================
= 方法二:不使用 parent仅用高度树形 DP =
= 思路:一次 DFS自底向上 =
====================================================*/
int diameterByHeight = 0;
/*
返回:
- 以当前节点为起点,向下的最大深度
*/
int depth(TreeNode* root) {
if (!root) return 0;
int L = depth(root->left);
int R = depth(root->right);
// 更新直径:经过当前节点的最长路径
diameterByHeight = max(diameterByHeight, L + R);
// 返回当前子树高度
return max(L, R) + 1;
}
/*
使用高度法求直径
*/
int diameterWithHeight(TreeNode* root) {
diameterByHeight = 0;
depth(root);
return diameterByHeight;
}
/*====================================================
= main =
====================================================*/
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
/*
示例二叉树
1
/ \
2 3
/ \
4 5
\
6
直径路径4 - 2 - 1 - 3 - 5 - 6
直径长度5边数
*/
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->left->left = new TreeNode(4);
root->right->right = new TreeNode(5);
root->right->right->right = new TreeNode(6);
cout << "Diameter (with parent / BFS): "
<< diameterWithParent(root) << '\n';
cout << "Diameter (by height / DFS): "
<< diameterWithHeight(root) << '\n';
return 0;
}

92
模板/树/树转图.cpp Normal file
View File

@@ -0,0 +1,92 @@
#include <unordered_map>
#include <vector>
#include <deque>
using namespace std;
/*
二叉树节点定义
*/
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
};
/*
图的邻接表表示
key : 树节点指针
value : 与该节点相邻的节点列表
*/
unordered_map<TreeNode*, vector<TreeNode*>> adj;
/*
BFS 访问标记
防止在“树转无向图”后出现来回走
*/
unordered_map<TreeNode*, bool> visited;
/*
将二叉树转换为无向图
本质:父 <-> 子 建立双向边
*/
void TreeNodeToGraph(TreeNode* root) {
if (root == nullptr) return;
// 如果有左孩子,建立 root <-> left 的双向边
if (root->left != nullptr) {
adj[root].push_back(root->left);
adj[root->left].push_back(root);
TreeNodeToGraph(root->left);
}
// 如果有右孩子,建立 root <-> right 的双向边
if (root->right != nullptr) {
adj[root].push_back(root->right);
adj[root->right].push_back(root);
TreeNodeToGraph(root->right);
}
}
/*
从 target 出发做 BFS
返回:与 target 距离恰好为 step 的所有节点
*/
deque<TreeNode*> BFS(TreeNode* target, int step) {
deque<TreeNode*> q;
q.push_back(target);
visited[target] = true;
int dist = 0;
while (!q.empty()) {
int cnt = q.size(); // 当前层节点数
// 如果已经到达目标层,直接返回这一层的所有节点
if (dist == step) {
return q;
}
// 扩展当前层
for (int i = 0; i < cnt; i++) {
TreeNode* node = q.front();
q.pop_front();
// 遍历邻接节点
for (TreeNode* nxt : adj[node]) {
if (!visited[nxt]) {
visited[nxt] = true;
q.push_back(nxt);
}
}
}
dist++;
}
// 如果 step 超过树高度,返回空
return {};
}

177
模板/树/表达式树.cpp Normal file
View File

@@ -0,0 +1,177 @@
#include <iostream>
#include <stack>
#include <vector>
#include <string>
#include <cctype>
using namespace std;
/*
表达式树节点
*/
struct ExprNode {
char op; // 运算符,若是操作数则无意义
int val; // 操作数值,仅在叶子节点有效
ExprNode* left;
ExprNode* right;
// 构造操作数节点
ExprNode(int v) : op(0), val(v), left(nullptr), right(nullptr) {}
// 构造运算符节点
ExprNode(char c, ExprNode* l, ExprNode* r)
: op(c), val(0), left(l), right(r) {}
};
/*
判断是否为运算符
*/
bool isOperator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/';
}
/*
运算符优先级
*/
int priority(char c) {
if (c == '+' || c == '-') return 1;
if (c == '*' || c == '/') return 2;
return 0;
}
/*
中缀表达式转后缀表达式Shunting-yard 算法)
*/
vector<string> infixToPostfix(const string& s) {
vector<string> postfix;
stack<char> ops;
for (int i = 0; i < (int)s.size(); ) {
// 读取数字(支持多位数)
if (isdigit(s[i])) {
int num = 0;
while (i < (int)s.size() && isdigit(s[i])) {
num = num * 10 + (s[i] - '0');
i++;
}
postfix.push_back(to_string(num));
}
// 左括号直接入栈
else if (s[i] == '(') {
ops.push(s[i]);
i++;
}
// 右括号:弹到遇见左括号
else if (s[i] == ')') {
while (!ops.empty() && ops.top() != '(') {
postfix.push_back(string(1, ops.top()));
ops.pop();
}
ops.pop(); // 弹出 '('
i++;
}
// 运算符
else if (isOperator(s[i])) {
while (!ops.empty() &&
priority(ops.top()) >= priority(s[i])) {
postfix.push_back(string(1, ops.top()));
ops.pop();
}
ops.push(s[i]);
i++;
}
// 跳过空格等非法字符
else {
i++;
}
}
// 清空操作符栈
while (!ops.empty()) {
postfix.push_back(string(1, ops.top()));
ops.pop();
}
return postfix;
}
/*
后缀表达式构建表达式树
*/
ExprNode* buildExpressionTree(const vector<string>& postfix) {
stack<ExprNode*> st;
for (auto& token : postfix) {
// 操作数
if (isdigit(token[0])) {
st.push(new ExprNode(stoi(token)));
}
// 运算符
else {
ExprNode* right = st.top(); st.pop();
ExprNode* left = st.top(); st.pop();
st.push(new ExprNode(token[0], left, right));
}
}
return st.top();
}
/*
递归计算表达式树的值
*/
int evaluate(ExprNode* root) {
if (!root) return 0;
// 叶子节点:操作数
if (root->op == 0) {
return root->val;
}
int l = evaluate(root->left);
int r = evaluate(root->right);
switch (root->op) {
case '+': return l + r;
case '-': return l - r;
case '*': return l * r;
case '/': return l / r; // 默认题目保证可整除
}
return 0;
}
/*
中序遍历(带括号,便于验证结构)
*/
void inorder(ExprNode* root) {
if (!root) return;
if (root->op) cout << '(';
inorder(root->left);
if (root->op) cout << root->op;
else cout << root->val;
inorder(root->right);
if (root->op) cout << ')';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
string expr;
getline(cin, expr); // 读取一整行表达式
// 中缀 → 后缀
vector<string> postfix = infixToPostfix(expr);
// 后缀 → 表达式树
ExprNode* root = buildExpressionTree(postfix);
// 输出表达式值
cout << evaluate(root) << '\n';
// 可选:输出中序遍历结果
// inorder(root);
return 0;
}