NewCodeTemplate
This commit is contained in:
76
模板/树/Huffman.cpp
Normal file
76
模板/树/Huffman.cpp
Normal 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;
|
||||
}
|
||||
24
模板/树/Huffman最小代价.cpp
Normal file
24
模板/树/Huffman最小代价.cpp
Normal 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;
|
||||
}
|
||||
51
模板/树/LCA最近共同祖先.cpp
Normal file
51
模板/树/LCA最近共同祖先.cpp
Normal 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;
|
||||
}
|
||||
186
模板/树/两序重建树.cpp
Normal file
186
模板/树/两序重建树.cpp
Normal 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;
|
||||
}
|
||||
35
模板/树/前序遍历路径.cpp
Normal file
35
模板/树/前序遍历路径.cpp
Normal 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;
|
||||
}
|
||||
};
|
||||
209
模板/树/增强前序遍历建树.cpp
Normal file
209
模板/树/增强前序遍历建树.cpp
Normal 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
94
模板/树/并查集.cpp
Normal 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
166
模板/树/树的直径.cpp
Normal 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
92
模板/树/树转图.cpp
Normal 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
177
模板/树/表达式树.cpp
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user