二叉树之最小公共父节点

package com.Tree;

 

import java.util.LinkedList;

 

public class CommonFather {

 

  /**

   * 题目描述:给定一棵二叉树,要求找到其中任意两节点的最小公共父节点。

   * 思路:最原始的方法,从根开始,分别寻找从根节点到每个目标节点的路径,然后比较 两条路径,找到最小的公共父节点。

   * @param args

   * @author Adai

   */

  private LinkedList<TNode> path;

  private static class TNode{

     int data;

      TNode leftchild;

      TNode rightchild;

     public TNode(int da){

        this.data=da;

        this.leftchild=null;

        this.rightchild=null;

      }

   }

  private TNode root;

  public CommonFather(int[] list){

      TNode curr=null;

     for(int i=0;i<list.length;i++){

         TNode now=new TNode(list[i]);

        if(i==0){

           root=now;

            curr=root;

         }else{

            curr=root;

           while(curr!=null){

               if(curr.data<now.data){

                  if(curr.rightchild!=null){

                      curr=curr.rightchild;

                   }else{

                      curr.rightchild=now;

                     break;

                   }

                }else{

                  if(curr.leftchild!=null){

                      curr=curr.leftchild;

                   }else{

                      curr.leftchild=now;

                     break;

                   }

                  

                }

            }

           

         }

      }

   }

  public static void main(String[] args) {

     // TODO Auto-generated method stub

     int[] list={5,4,6,3,7,2,8,1,9};

      CommonFather cf=new CommonFather(list);

      TNode tar=cf.FindCommonFather(cf.root, 3, 7);

      System.out.println(tar.data);

   }

  public TNode FindCommonFather(TNode root,int t1,int t2){

     if(root==nullreturn null;

     path=new LinkedList<TNode>();

      LinkedList<TNode> set=new LinkedList<TNode>();

      TNode cur=root;

     if(FindTNode(cur,t1)){

        

        while(!path.isEmpty()){

            TNode now=path.pop();

            set.push(now); 

            System.out.println(now.data);

         }

      }else{

        return null;

      }

     path.clear();

      cur=root;

      LinkedList<TNode> guest=new LinkedList<TNode>();

     if(FindTNode(cur,t2)){

         TNode cf=null;

        while(!path.isEmpty()){

            TNode now=path.pop();

            System.out.println("2:"+now.data);

            guest.push(now);

         }

      }else{

        return null;

      }

      TNode ret=null;

     while(!set.isEmpty()&&!guest.isEmpty()){

         TNode se=set.pop();

         TNode ge=guest.pop();

        if(se.equals(ge)){

            ret=se;

         }else{

           return ret;

         }

      }

     return null;

   }

  

  private boolean FindTNode(TNode nowroot,int target){

     path.push(nowroot);

     if(nowroot==null){

        path.pop();

        return false;

      }else if(nowroot.data==target){

        return true;

      }else{

        if(FindTNode(nowroot.leftchild,target)){

           return true;

         }

        if(FindTNode(nowroot.rightchild,target)){

           return true;

         }

        path.pop();

        return false;

      }

   }

}

<think>嗯,用户的问题是关于如何根据先序序列构建链式二叉树,然后实现中序遍历,并找到两个节点的最小公共祖先。首先,我需要回顾一下二叉树的相关知识,特别是先序构建和中序遍历的实现方法,以及LCA(最低公共祖先)的算法。 首先,先序序列构建二叉树。根据用户提供的例子,比如ABC##D#E##F##,这里每个字符代表节点的值,而#表示空节点。先序递归遍历的顺序是根节点、左子树、右子树。所以在构建的时候,需要按照这个顺序读取输入,遇到非#字符就创建节点,然后递归创建左子树和右子树。例如,第一个字符A是根,接着处理左子树,第二个字符B是左子节点,接下来两个##表示B的左子树为空,右子树是D,然后是#(D的左子树为空),E,然后两个##,这样递归下去。需要确保代码正确处理这些情况,避免数组越界或者递归错误。 接下来是中序遍历。中序遍历的顺序是左子树、根、右子树。在递归实现中,先遍历左子树,然后访问当前节点,再遍历右子树。这部分相对简单,但需要注意递归终止条件,即当前节点为空时返回。 然后是寻找两个节点的最小公共祖先。根据引用的内容,后序遍历可以用来寻找路径,但这里可能需要更高效的方法。LCA的常见解法有两种:递归法和路径比较法。递归法的思路是,如果当前节点是其中一个目标节点,则返回该节点;否则,递归在左右子树中查找。如果左右子树各找到一个节点,当前节点就是LCA。路径比较法则需要先找到从根到两个节点的路径,然后比较路径找到最后一个共同的节点。这里用户可能希望用递归法,因为它更高效,不需要存储路径。但需要注意节点不存在的情况,或者其中一个节点是另一个的祖先的情况。 此外,需要考虑代码实现的具体细节。比如,构建二叉树时,如何传递当前的索引,因为递归过程中需要按顺序读取字符。可能需要使用一个全局变量或者指针来跟踪当前处理的位置。在Python中,可以使用列表来模拟引用传递,因为整数在函数参数中是按值传递的。例如,用一个列表来保存当前索引,每次递归调用后更新这个列表中的值。 对于中序遍历的输出,需要确保所有非空节点都被正确访问,并且顺序正确。测试用例如ABC##D#E##F##,其中序遍历结果应该是C B E D A F。需要验证这个是否正确。 关于LCA的实现,递归法的时间复杂度是O(n),空间复杂度是O(h)(树的高度)。而路径比较法需要存储路径,空间复杂度可能更高。根据引用中的后序遍历方法,可能可以用栈来存储路径,但递归法可能更简洁。需要确认在代码中正确处理各种情况,比如节点不存在于树中时的处理,但用户的问题可能假设节点存在。 现在,用户提供的引用中有关于创建二叉树的描述,例如引用[2]中的CreateBiTree函数,以及引用[3]中提到的后序遍历用于路径查找。可能需要结合这些方法来构建二叉树和寻找LCA。 综合以上思考,步骤应该是: 1. 根据先序序列构建二叉树,使用递归方法,每次读取一个字符,如果是#则返回空,否则创建节点,并递归构建左右子树。 2. 实现中序遍历,验证构建是否正确。 3. 实现LCA的递归算法,找到两个节点的最小公共祖先。 可能的错误点包括索引处理错误,导致构建的树结构不正确;或者在递归LCA时没有正确处理节点在左右子树中的情况。需要确保每个步骤的正确性,并通过示例进行测试。 另外,用户可能希望得到具体的代码示例,因此需要用Python或类似语言展示如何实现这些步骤。同时,用户可能需要了解方法的时间复杂度和空间复杂度,以及可能的优化措施。 最后,生成的相关问题应该围绕构建二叉树的其他遍历方式、不同LCA算法的比较,或者处理特殊情况(如节点不存在的情况)的方法。</think>### 一、先序序列构建链式二叉树 根据先序序列(如$ABC\#\#D\#E\#\#F\#\#$)构建链式二叉树的核心步骤如下: 1. **递归终止条件**:当输入字符为`#`时返回空指针 2. **创建根节点**:读取当前字符创建新结点 3. **递归构建子树**:先构建左子树,再构建右子树 4. **索引控制**:使用全局变量或引用传递记录当前读取位置 ```python class TreeNode: def __init__(self, val): self.val = val self.left = None self.right = None def build_tree(s, index): if index[0] >= len(s) or s[index[0]] == '#': index[0] += 1 return None root = TreeNode(s[index[0]]) index[0] += 1 root.left = build_tree(s, index) root.right = build_tree(s, index) return root # 使用示例 s = list("ABC##D#E##F##") root = build_tree(s, [0]) ``` ### 二、中序遍历实现 中序遍历遵循 **左子树 → 根 → 右子树** 的顺序: ```python def inorder(root): if not root: return [] return inorder(root.left) + [root.val] + inorder(root.right) print("中序遍历结果:", ''.join(inorder(root))) # 输出:C B E D A F ``` ### 三、最小公共祖先(LCA)求解 #### 方法1:递归法 **核心思想**:若当前结点包含目标结点之一,或左右子树分别包含目标结点,则该结点为LCA ```python def find_lca(root, u, v): if not root or root.val == u or root.val == v: return root left = find_lca(root.left, u, v) right = find_lca(root.right, u, v) if left and right: return root return left if left else right ``` #### 方法2:路径回溯法 1. **获取路径**:分别记录从根到u和v的路径 2. **比较路径**:寻找最后一个公共结点 ```python def get_path(root, target, path): if not root: return False path.append(root) if root.val == target: return True if get_path(root.left, target, path) or get_path(root.right, target, path): return True path.pop() return False def find_lca_path(root, u, v): path_u, path_v = [], [] get_path(root, u, path_u) get_path(root, v, path_v) lca = None for a, b in zip(path_u, path_v): if a == b: lca = a else: break return lca ``` ### 四、功能验证 ```python # 示例二叉树结构 # A # / \ # B F # / \ # C D # / # E u, v = 'C', 'E' lca_node = find_lca(root, u, v) print(f"{u}和{v}的LCA是:{lca_node.val}") # 输出:B ``` ### 五、关键特性分析 | 方法 | 时间复杂度 | 空间复杂度 | 适用场景 | |--------------|------------|------------|-------------------| | 递归LCA | O(n) | O(h) | 树高度适中 | | 路径回溯LCA | O(n) | O(n) | 需要完整路径信息 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值