Files
Data-Structure/模板//树的直径.cpp
2025-12-16 20:36:27 +08:00

167 lines
3.8 KiB
C++
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.

#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;
}