【剑指Offer-二叉树】面试题8:二叉树的下一个节点

题目描述

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

思路1

二叉树的中序遍历顺序为:左孩子,根,右孩子。而一个节点也只会有3种情况:该节点是其父节点的左孩子;该节点是其父节点的右孩子;该节点无父节点,是根节点。根据是否包含右孩子,可以把这3种情况的每一种继续细分为2种情况。下面对这3种情况逐个分析:
1、该节点是其父节点的左孩子。这时可以细分为两种情况:该节点有右子树和没有右子树:
1.1、该节点有右子树,则该节点的下一个节点就是右子树的最左节点;
1.2、该节点没有右子树,则根据中序遍历规则,该节点的下一个节点为其父节点;
2、该节点是其父节点的右孩子。这时可以再细分为两种情况:该节点有右子树和没有右子树:
2.1、该节点有右子树,同1.1;
2.2、该节点没有右子树,则沿着父节点指针一直向上遍历,直到找到一个是其父节点左孩子的节点;
3、该节点没有父节点,为根结点。这时也可以细分为两种情况:该节点有右子树和没有右子树:
3.1、该节点有右子树:和1.1相同;
3.2、该节点没有右子树,则下一个节点为空。
对应的代码如下:

/*
struct TreeLinkNode {
    int val;
    struct TreeLinkNode *left;
    struct TreeLinkNode *right;
    struct TreeLinkNode *next;    //父节点
    TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
        
    }
};
*/
class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode)
    {
        TreeLinkNode* node = nullptr;
        if(pNode==nullptr)
            return node;
        if(pNode->next!=nullptr) //不是根结点
        {
            if(pNode->next->left==pNode)    //左子树
            {
                if(pNode->right==nullptr)    //左子树有右子树
                    node = pNode->next;
                else{    //左子树没有右子树
                    node = pNode->right;
                    while(node->left!=nullptr){
                        node = node->left;
                    }
                }
            }
            else{    //右子树
                if(pNode->right==nullptr){    //右子树没有右子树
                    TreeLinkNode* cur = pNode;
                    TreeLinkNode* parent = pNode->next;
                    while(parent && parent->right==cur){
                        cur = parent;
                        parent = parent->next;
                    }
                    node = parent;
                }
                else{    //右子树有右子树
                    node = pNode->right;
                    while(node->left!=nullptr)
                        node = node->left;
                    }
                }        
        }
        else{    //根结点
            if(pNode->right!=nullptr){    //根结点有右子树
                node = pNode->right;
                while(node->left!=nullptr)
                    node = node->left;
            }
        }
        return node;
    }
};

思路2

思路1有点麻烦,但比较好想。可以把情况简化到3种,这也是书上的做法:
1、该节点有右孩子,那么下一个节点就是其右孩子的最左子结点;
2、该节点没有右孩子并且该节点是其父节点的左孩子,那么下一个节点使就是其父节点;
3、该节点没有右孩子并且该节点是其父节点的右孩子,则沿着父节点指针一直向上遍历,直到找到一个是其父节点左孩子的节点;
对应代码如下:

/*
struct TreeLinkNode {
    int val;
    struct TreeLinkNode *left;
    struct TreeLinkNode *right;
    struct TreeLinkNode *next;
    TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
        
    }
};
*/
class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode)
    {
        TreeLinkNode* node = nullptr;
        if(pNode==nullptr)
            return node;
        if(pNode->right!=nullptr){
            node = pNode->right;
            while(node->left!=nullptr)
                node = node->left;
        }
        else if(pNode->next!=nullptr){
            if(pNode->next->left==pNode)
                node = pNode->next;
            else{
                TreeLinkNode* cur = pNode;
                TreeLinkNode* parent = pNode->next;
                while(parent!=nullptr && parent->right==cur){
                    cur = parent;
                    parent = parent->next;
                }
                node = parent;
            }
        }
        return node;
    }
};
posted @ 2020-02-18 20:17  Flix  阅读(156)  评论(0编辑  收藏  举报