JZ8 二叉树的下一个结点


JZ8 二叉树的下一个结点

描述

给定一个二叉树其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的next指针。

输入描述:

输入分为2段,第一段是整体的二叉树,第二段是给定二叉树节点的值,后台会将这2个参数组装为一个二叉树局部的子树传入到函数GetNext里面,用户得到的输入只有一个子树根节点。

返回值描述:

返回传入的子树根节点的下一个节点,后台会打印输出这个节点。

示例1

输入:

{8,6,10,5,7,9,11},8

返回值:

9

示例2

输入:

{8,6,10,5,7,9,11},6

返回值:

7

示例3

输入:

{1,2,#,#,3,#,4},4

返回值:

1

示例4

输入:

{5},5

返回值:

"null"
// 不存在,后台打印"null" 

解析

本题要求寻找输入的二叉树节点在中序遍历中的下一个节点,涉及到了中序遍历的顺序,很容易想到的一个方法是进行一次中序遍历,用数组按顺序保存所有的节点,遍历完后再在数组中寻找输入节点的下一个节点。

代码清单

import java.util.ArrayList;
/*
public class TreeLinkNode {
    int val;
    TreeLinkNode left = null;
    TreeLinkNode right = null;
    TreeLinkNode next = null;

    TreeLinkNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    private ArrayList nodeList = new ArrayList<>();
    public TreeLinkNode GetNext(TreeLinkNode pNode) {
        // 传入的是树中的某一节点,需要先找到树的根节点
        TreeLinkNode root = pNode;
        while(root.next!=null)
            root = root.next;
        MidOrder(root);
        for(int i = 0;i

这种方式容易想到,实现也简单,空间复杂度为O(n),时间复杂度为O(n)。不过要是为了这种简单方式写一篇笔记属实小题大做了,所以还要研究更简单的方法!

考虑中序遍历中下一个节点的问题,以这么一颗二叉树为例,有三种情况

  1. 当前节点有右孩子,则下一个节点是当前节点右子树中的最左节点。即若当前节点为 B,则下一个节点为 H。
  2. 当前节点无右孩子,且自身是父节点的左孩子,则下一个节点是当前节点的父节点。即若当前节点为 H,则下一个节点为 E。
  3. 当前节点无右孩子,且自身是父节点的右孩子,说明当前节点是子树中的最后一个节点,需要往上追溯到是某个节点左孩子的祖先节点,下一个节点就是该祖先节点的父节点,若找不到这样的祖先节点,则自身没有下一个节点。即若当前节点为 I,说明 B 子树已经遍历完毕,且祖先节点 B 是其父节点 A 的左孩子,则下一个节点是 A;若当前接地那为 G,说明 C 子树已经遍历完毕,且找不到一个祖先节点是其父节点的左孩子,说明没有下一个节点。

可以看出有两个步骤,第一步是判断自己是否有右孩子,这是由中序遍历左根右的顺序决定的,若有右孩子则需要在右孩子中寻找第一个节点;若没有则进入第二步,判断自己是左孩子还是右孩子,若是左孩子,则根据左根右的顺序,下一个是根,即父节点;若是右孩子,说明当前子树遍历完了(自身是右孩子且自身没有右孩子),需要找到当前遍历完的是左子树还是右子树,若是左子树,则下一个节点是该左子树的父节点,若是右子树,则全部遍历已经完成。

代码清单

/*
public class TreeLinkNode {
    int val;
    TreeLinkNode left = null;
    TreeLinkNode right = null;
    TreeLinkNode next = null;

    TreeLinkNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public TreeLinkNode GetNext(TreeLinkNode pNode) {
        TreeLinkNode temp = null;
        // 当前节点有右孩子,下一个节点是右孩子中的最左节点
        if(pNode.right != null){
            // 寻找右孩子的最左节点
            temp = pNode.right;
            while( temp.left != null)
                temp = temp.left;
            return temp;
        }
        // 过了上面说明当前节点无右孩子
        // 自身是父节点的左孩子,则下一个节点是父节点
        if(pNode.next != null && pNode == pNode.next.left)
            return pNode.next;
        // 自身是父节点的右孩子,需要寻找为左子树的祖先节点
        if(pNode.next != null && pNode == pNode.next.right){
            temp = pNode;
            while(temp.next != null){
                if(temp == temp.next.left)
                    return temp.next;
                temp = temp.next;
            }
        }
        return null;
    }
}

这种方式的空间复杂度为O(1),时间复杂度为O(n),比之前的方式要好一点。

总结

也没什么好说的,第一种方式记录了全部顺序,比较暴力,第二种方式对中序遍历的情况进行了考量,单独进行三种情况的判断即可!当然从本题树的结构中有父节点的指针可以看出,比较合理的应该也是第二种方式。

相关