将普通树转为二叉树

普通树转化为二叉树!

普通树转化为二叉树!

普通树转化为二叉树!

重要的事情说三遍(

 

最近在刷树形dp的题,而树形dp的某些特殊题目多依靠二叉树的结构写出状态转移方程,所以专门看看不得不说说的普通树(多叉树)转二叉树。

 

上图!(没图我说个jb

 

如图有一颗生长健康饱满有活力的树,但是仔细看看可以发现节点2有三个儿子,即这并不是我们想要的二叉树。

 

怎么办?

 

留长子:

 

剔除所有节点除大儿子以外的所有儿子


养兄弟:

每个无父亲节点指向长兄


至此,一颗多叉树顺利转变为我们想要的二叉树

下面附上源代码/pas:

var
  i,x,y:longint;
  b:array[0..100]of longint;
begin
  readln(n,m);
  fillchar(b,sizeof(b),0);
  for i:=1 to n do
  begin
    readln(x,y);
    if b[x]=0 then t[x].l:=y
    else t[b[x]].r:=y;
    b[x]:=y;
  end;
end;


 

将一棵**普通树**(即每个节点可以有任意多个子节点的,也称为多叉转化为**二叉树**,通常采用的是“**左孩子-右兄弟表示法**”(Left-Child Right-Sibling Representation)。 这种方法可以在不丢失结构信息的前提下,将任意多叉转换为等价的二叉树形式。这种转换在数据结构中非常常见,尤其用于实现 **堆合并操作** 或 **森林转二叉树**。 --- ### ✅ 转换规则:左孩子-右兄弟表示法 对于普通树中的每一个节点: - **左指针** 指向它的 **第一个子节点**(最左边的孩子) - **右指针** 指向它的 **下一个兄弟节点**(右边的兄弟) 这样,每个节点最多两个指针:左(孩子)、右(兄弟),构成一棵二叉树--- ### 🔁 转换步骤 给定一个普通树节点定义如下: ```cpp struct GeneralTreeNode { int val; std::vector<GeneralTreeNode*> children; }; ``` 我们要将其转换为: ```cpp struct BinaryTreeNode { int val; BinaryTreeNode* left; // 第一个孩子 BinaryTreeNode* right; // 下一个兄弟 }; ``` #### 转换过程: 1. 当前节点的 `left` 指向其第一个子节点(递归转换)。 2. 所有子节点通过 `right` 链接成一条链表(兄弟关系)。 3. 递归处理每个子节点。 --- ### ✅ C++ 实现代码 ```cpp #include <iostream> #include <vector> // 普通树节点 struct GeneralTreeNode { int val; std::vector<GeneralTreeNode*> children; explicit GeneralTreeNode(int x) : val(x) {} }; // 二叉树节点(用于表示左孩子-右兄弟) struct BinaryTreeNode { int val; BinaryTreeNode* left; BinaryTreeNode* right; explicit BinaryTreeNode(int x) : val(x), left(nullptr), right(nullptr) {} }; // 将普通树转换为二叉树(左孩子-右兄弟表示法) BinaryTreeNode* generalToBinary(GeneralTreeNode* root) { if (!root) return nullptr; BinaryTreeNode* binaryRoot = new BinaryTreeNode(root->val); if (!root->children.empty()) { // 左孩子:第一个子节点 binaryRoot->left = generalToBinary(root->children[0]); // 将其余兄弟连接为右链 BinaryTreeNode* current = binaryRoot->left; for (size_t i = 1; i < root->children.size(); ++i) { current->right = generalToBinary(root->children[i]); current = current->right; } } return binaryRoot; } // 辅助函数:打印二叉树(中序遍历观察结构) void inorder(BinaryTreeNode* root) { if (!root) return; inorder(root->left); std::cout << "Node: " << root->val << "\n"; inorder(root->right); } ``` --- ### 🌲 示例转换 原始普通树: ``` A / | \ B C D / \ | E F G ``` 转换后的二叉树(左孩子-右兄弟): ``` A \ B —— C —— D \ \ E —— F G ``` 实际二叉树结构为: ``` A / B / \ E C \ \ F D \ G ``` 解释: - A 的左孩子是 B(第一个孩子) - B 的右兄弟是 C,C 的右兄弟是 D - B 的左孩子是 E,E 的右兄弟是 F - D 的左孩子是 G --- ### 🔄 反向转换(可选扩展) 你也可以从二叉树还原回普通树,只要遵循: - 每个节点的 `left` 是孩子链表头 - `right` 是兄弟链表 --- ### 💡 应用场景 | 场景 | 说明 | |------|------| | **森林转二叉树** | 多棵组成的森林可用此法统一转为一棵二叉树 | | **堆合并(如左偏)** | 利用右兄弟表示法模拟多路分支 | | **节省指针空间** | 不需要动态数组存储孩子,只需两个指针 | --- ### ❗ 注意事项 - 转换后虽然逻辑结构一致,但**不再是搜索**,不能按 BST 规则查找。 - 这种二叉树仅用于**结构表示**,而非排序或高效查询。 - 原始父子关系通过路径恢复:沿着 `left` 和 `right` 向下找。 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值