一、题目

给定一个二叉树其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的next指针。下图为一棵有9个节点的二叉树。树中从父节点指向子节点的指针用实线表示,从子节点指向父节点的用虚线表示

剑指Offer面试题8:二叉树的下一个结点_结点

示例:

输入:{8,6,10,5,7,9,11},8

返回:9

解析:这个组装传入的子树根节点,其实就是整颗树,中序遍历{5,6,7,8,9,10,11},根节点8的下一个节点就是9,应该返回{9,10,11},后台只打印子树的下一个节点,所以只会打印9,如下图,其实都有指向左右孩子的指针,还有指向父节点的指针,下图没有画出来

剑指Offer面试题8:二叉树的下一个结点_父节点_02

二、题解

2.1 中序遍历递归

分析:

递归是一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。因此递归过程最重要的就是看能不能将原本的问题分解为更小的子问题了,这是使用递归的关键。

二叉树的递归,则是将某个节点的左子树、右子树看成一棵完整的树,那么对于子树的访问或者操作就是对于原树的访问或者操作的子问题。

思路:

根据给定输入中的节点指针向父级进行迭代,直到找到该树的根节点,然后根据根节点进行中序遍历,当遍历到和给定树节点形同的节点时,下一个节点就是我们要找的节点。

具体做法:

1、首先根据给出的节点向父级迭代找到根节点

2、然后在根节点进行中序遍历

3、将中序遍历的结果存储下来

4、拿当前节点匹配是否有符合要求的下一个节点

Java实现:

import java.util.*;
public class Solution {
    ArrayList<TreeLinkNode> nodes = new ArrayList<>();
    public TreeLinkNode GetNext(TreeLinkNode pNode) {
        // 获取根节点
        TreeLinkNode root = pNode;
        while(root.next != null) root = root.next;
        
        // 中序遍历打造nodes
        InOrder(root);
        
        // 进行匹配
        int n = nodes.size();
        for(int i = 0; i < n - 1; i++) {
            TreeLinkNode cur = nodes.get(i);
            if(pNode == cur) {
                return nodes.get(i+1);
            }
        }
        return null;
    }
    
    // 中序遍历
    void InOrder(TreeLinkNode root) {
        if(root != null) {
            InOrder(root.left);
            nodes.add(root);
            InOrder(root.right);
        }
    }
}

2.2 分类直接寻找

思路:

1、如果给出的节点有右子节点,则最终要返回的下一个节点即右子树的最左下的节点

2、如果给出的节点无右子节点,且当前节点是其父节点的左子节点,则返回其父节点

3、如果给出的节点无右子节点,且当前节点是其父节点的右子节点,则先要沿着左上方父节点爬树,一直爬到当前节点是其父节点的左子节点为止,返回的就是这个父节点;或者没有满足上述情况的则返回为NULL

具体做法:

1、判断该节点是否符合思路中的第一点,则一直找到右子树的左下节点为止为返回值

2、判断该节点是否符合思路中的第二点,则返回当前节点的父节点

3、判断该节点是否符合思路中的第三点,则迭代向上找父节点,直到迭代的当前节点是父节点的左孩子节点为止,返回该父节点了如果不满足上述情况返回NULL

剑指Offer面试题8:二叉树的下一个结点_父节点_03

Java实现

import java.util.*;
public class Solution {
    public TreeLinkNode GetNext(TreeLinkNode pNode) {
        // 情况一
        if(pNode.right != null) {
            TreeLinkNode rchild = pNode.right;
            // 一直找到右子树的最左下的结点为返回值
            while(rchild.left != null) rchild = rchild.left; 
            return rchild;
        }
        
        // 情况二
        if(pNode.next != null && pNode.next.left == pNode) {
            return pNode.next;
        }
        
        // 情况三
        if(pNode.next != null) {
            TreeLinkNode ppar = pNode.next;
            // 沿着左上一直爬树,爬到当前结点是其父节点的左自己结点为止
            while(ppar.next != null && ppar.next.right == ppar) ppar = ppar.next; 
            return ppar.next;
        }
        return null;
    }
}