输入两棵二叉树A和B,判断B是不是A的子结构

树的子结构

题目:输入两棵二叉树A和B,判断B是不是A的子结构。

二叉树结点的定义如下:

struct BinaryTreeNode
{
    int             m_nValue;
    BinaryTreeNode *m_pLeft;
    BinaryTreeNode *m_pRight;
};

例如图中的两棵二叉树,由于A中有一部分子树的结构和B是一样的,因此B是A的子结构。

要查找树A中是否存在和树B结构一样的子树,可以分成两步:

  1. 第一步在树A中找到和B的根节点的值一样的结点R;
  2. 第二步再判断树A中以R为根结点的子树是不是包含和树B一样的结构。

第一步在树A中查找与根结点的值一样的结点,这实际上就是树的遍历。递归调用HasSubTree遍历二叉树A。如果发现某一结点的值和树B的头结点的值相同,则调用DoesTreeHavaTree2,做第二步判断。

第二步是判断树A中以R为根结点的子树是不是和树B具有相同的结构。

核心代码:

复制代码
 1 bool HasSubtree(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2)
 2 {
 3     bool result = false;
 4 
 5     if(pRoot1 != NULL && pRoot2 != NULL)
 6     {
 7         if(pRoot1->m_nValue == pRoot2->m_nValue)
 8             result = DoesTree1HaveTree2(pRoot1, pRoot2);
 9         if(!result)
10             result = HasSubtree(pRoot1->m_pLeft, pRoot2);
11         if(!result)
12             result = HasSubtree(pRoot1->m_pRight, pRoot2);
13     }
14 
15     return result;
16 }
17 
18 bool DoesTree1HaveTree2(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2)
19 {
20     if(pRoot2 == NULL)
21         return true;
22 
23     if(pRoot1 == NULL)
24         return false;
25 
26     if(pRoot1->m_nValue != pRoot2->m_nValue)
27         return false;
28 
29     return DoesTree1HaveTree2(pRoot1->m_pLeft, pRoot2->m_pLeft) &&
30         DoesTree1HaveTree2(pRoot1->m_pRight, pRoot2->m_pRight);
31 }
复制代码

注意在使用指针的时候一定要注意边界条件,即检查空指针。当树A或树B为空的时候,定义相应的输出。如果没有检查并做相应的处理,程序非常容易崩溃。

 

原文出处:http://www.cnblogs.com/heyonggang/archive/2013/11/03/3405482.html

<think>好的,我现在需要帮助用户解决关于如何用C++判断两棵二叉树是否相等的问题。用户提到使用二叉链表存储结构,并且参考了之前的引用内容。首先,我要回顾用户提供的引用资料,看看是否有可用的信息。 首先看引用[1],里面有一个判断两棵树结构是否相同的算法。用户提供的代码是一个递归函数,检查两个节点是否都为空,或者其中一个为空,然后递归检查左右子树。这给了我一个基础,但用户现在需要的是判断树是否相等,即不仅结构相同,节点的值也要相同。因此,我需要在这个基础上增加对节点值的比较。 接下来,引用[2]提到了二叉链表的存储结构,即左右孩子指针。这可能对理解数据结构有帮助,但用户的问题更多是关于算法实现。引用[3]中的层序遍历方法可能对非递归实现有参考价值,但用户可能需要递归或非递归两种方法。 用户之前的问题是关于交换二叉树左右孩子的代码实现,现在需要判断二叉树是否相等。可能需要比较两棵树的结构每个节点的值。因此,我需要结合结构检查值检查。 接下来,我需要确定如何实现这个功能。递归方法会比较直观,类似结构检查,但加上值的判断。非递归方法可以用队列或栈来实现层序或先序遍历,同时比较节点。 然后,我需要考虑测试用例,例如完全相同的树、结构不同、值不同等情况。还要注意内存管理输入格式,比如使用#表示空节点,这之前的代码一致。 用户可能还关心时间复杂度空间复杂度。递归方法的时间复杂度是O(n),空间复杂度是O(h),h是树的高度。非递归方法的空间复杂度可能更高,取决于使用的数据结构,比如队列或栈。 此外,需要处理边界情况,比如两棵树都为空,或者其中一棵为空的情况。还要确保在比较时,当前节点的值相等,再递归比较子树。 最后,根据用户之前的回答风格,应该提供代码示例、算法对比、测试用例常见问题解答,确保结构清晰,帮助用户理解。</think>### C++实现判断两棵二叉树是否相等(二叉链表存储) #### 一、算法原理 判断两棵二叉树相等需满足两个条件: 1. **结构相同**:对应结点位置必须同时存在或同时为空 2. **数值相同**:对应结点存储的数据必须相等 #### 二、完整代码实现 ```cpp #include <iostream> using namespace std; // 二叉树结点结构 struct BiTNode { char data; BiTNode *lchild, *rchild; BiTNode(char val) : data(val), lchild(nullptr), rchild(nullptr) {} }; // 递归创建二叉树(先序) BiTNode* CreateBiTree() { char ch; cin >> ch; if (ch == '#') return nullptr; BiTNode* node = new BiTNode(ch); node->lchild = CreateBiTree(); node->rchild = CreateBiTree(); return node; } // 递归判断相等(核心算法) bool IsEqual(BiTNode* t1, BiTNode* t2) { if (!t1 && !t2) return true; // 都为空 if (!t1 || !t2) return false; // 结构不同 if (t1->data != t2->data) return false; // 数值不同 return IsEqual(t1->lchild, t2->lchild) && IsEqual(t1->rchild, t2->rchild); } // 非递归层序判断(扩展实现) bool IsEqual_LevelOrder(BiTNode* t1, BiTNode* t2) { queue<BiTNode*> q1, q2; q1.push(t1); q2.push(t2); while (!q1.empty() && !q2.empty()) { auto *n1 = q1.front(); q1.pop(); auto *n2 = q2.front(); q2.pop(); if (!n1 && !n2) continue; if (!n1 || !n2) return false; if (n1->data != n2->data) return false; q1.push(n1->lchild); q1.push(n1->rchild); q2.push(n2->lchild); q2.push(n2->rchild); } return q1.empty() && q2.empty(); } int main() { cout << "创建第一棵树(#表示空): "; BiTNode* tree1 = CreateBiTree(); cout << "创建第二棵树(#表示空): "; BiTNode* tree2 = CreateBiTree(); cout << "递归判断结果: " << boolalpha << IsEqual(tree1, tree2) << endl; cout << "层序判断结果: " << boolalpha << IsEqual_LevelOrder(tree1, tree2); return 0; } ``` #### 三、算法对比 | 方法 | 时间复杂度 | 空间复杂度 | 特点 | |--------------|------------|------------|------------------------------| | 递归法 | $O(n)$ | $O(h)$ | 代码简洁,适合任意形态二叉树 | | 层序遍历法 | $O(n)$ | $O(n)$ | 避免递归栈溢出风险 | #### 四、测试用例 ```text // 用例1:完全相同的树 输入1: ABD##E##CF##G## 输入2: ABD##E##CF##G## 输出: true // 用例2:结构不同的树 输入1: AB##C## 输入2: A#B#C## 输出: false // 用例3:数值不同的树 输入1: A(B(D,E),C(F,G)) 输入2: A(B(D,E),C(X,G)) 输出: false ``` #### 五、关键实现细节 1. **递归终止条件** - 同时为空返回`true`(结构相同) - 单个为空返回`false`(结构不同) - 数值不同直接返回`false` 2. **非递归算法设计** - 使用两个队列进行同步层序遍历 - 入队顺序必须保持一致(左孩子→右孩子) - 队列同时为空时才判定为相等 3. **内存处理建议** - 实际项目中应添加析构函数释放内存 - 推荐使用智能指针管理结点生命周期 #### 六、常见问题解答 **Q1 如何处理不同遍历顺序的树?** 答:本算法基于**先序递归/层序**的严格位置对应判断。若两棵树只是遍历顺序不同但实际结构相同,仍会被正确识别为不同[^1]。 **Q2 空树如何处理?** 答:算法已包含空指针判断,当两棵空树比较时返回`true`,空树与非空树比较返回`false`[^3]。 **Q3 能否判断子树部分相同?** 答:本算法判断的是整树完全相等。若需判断子树包含关系,需修改终止条件为`if (!t2) return true`(即t2子树遍历完成即视为匹配)。 --- ### 相关问题拓展 1. **如何判断二叉树的相似性(仅结构相同)?** - 移除数值比较步骤,仅保留结构判断条件 2. **在分布式系统中如何比较大型二叉树?** - 采用哈希指纹技术:$Hash(root) = Hash(left) + data + Hash(right)$ 3. **如何处理带重复值的二叉树比较?** - 需要结合结构+数值双重验证,算法保持不变 [^1]: 递归判断逻辑参考lesson14-3的结构比较算法扩展 [^2]: 层序实现参考队列处理方案 [^3]: 空指针处理规范来自层序遍历实现经验
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值