08 二叉树的下一个节点

题目描述:

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

测试用例:

 1)普通二叉树(完全二叉树、不完全二叉树)

 2)特殊二叉树(所有节点都没有右/左子节点的二叉树,只有一个节点的二叉树,空树:根节点指针为nullptr)

 3)不同位置的节点的下一个节点(下一个节点为当前节点的右子节点、右子树的最左节点、父节点、跨层的父节点;当前节点没有下一个节点)

解题思路:

 建议:在解题时,画出具体的二叉树结构图、通过具体的例子找出中序遍历下一个节点的规律,设计可行的方法。

分三种情况讨论:

 1)如果一个节点有右子树,那么它的下一个节点就是它的右子树的最左节点。即从右子节点出发一直沿着左子节点的指针寻找。如图中b(h)与a(f)。

 2)该节点没有右子树,且该节点是其父节点的左节点,下一个节点是它的父节点。

 3)该节点没有右子树,且该节点是其父节点的右节点时:可以沿着指向父节点的指针一直向上遍历,直到找到一个是它父节点的左子节点的节点。如果这样的节点存在,那么这个节点的父节点就是要找的下一个节点

 4)初始化要找的下一个节点时,设为空指针。没有找到时,直接返回该空指针。

代码:

 1)

/*
struct TreeLinkNode {
    int val;
    struct TreeLinkNode *left;  //此处的struct对调用有影响么?没有
    struct TreeLinkNode *right;
    struct TreeLinkNode *next;
    TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
        
    }
};
*/
class Solution {
public:
    //pNode: 给定的节点 不要修改其值
    TreeLinkNode* GetNext(TreeLinkNode* pNode)
    {
         if( pNode == NULL ) //nullptr
             return NULL;
         //TreeLinkNode* nextNode = NULL ;
         TreeLinkNode* nextNode = nullptr ;
         //TreeLinkNode* nextNode = new TreeLinkNode();
         if (pNode->right != NULL){
             //error : 右子树非空,右子树的root节点则是指定节点pNode中序的下一个节点。
             //nextNode = pNode->right;
             //右子树非空,右子树的最左节点则是指定节点pNode中序的下一个节点。
             TreeLinkNode* rightTree = pNode->right ;
             while(rightTree->left!=NULL){
                 rightTree = rightTree->left ;
             }
             //把找到的左节点赋给返回值
             nextNode = rightTree;
         }else if (pNode->next!= nullptr){ //父节点非空--根节点没有父节点
             //右子树为空时,根据父节点判断指定节点pNode是左子树还是右子树
             if(pNode == pNode->next->left){
                 //是左节点,则在中序遍历中父节点是该节点的下一个节点
                 nextNode = pNode->next ;
             }else{
                 //是右节点
                 //父节点是左节点,取父节点的父节点。父节点是右节点,对父节点的父节点重新判断。。。
                 //一直找到父节点是左节点的节点。
                 TreeLinkNode* parantNode = pNode->next ;
                 TreeLinkNode* currentNode = pNode ;
                 while(parantNode!=nullptr && currentNode == parantNode->right){
                     currentNode = parantNode;
                     parantNode = parantNode->next ;
                 }
                 nextNode = currentNode->next ;
             }
             
         }
          return nextNode;
    }
};  

 注意:

「1」注意中英文字符

「2」line22-28,当右子树非空时,下一个节点应该时右子树的最左节点,而不是根节点。

「3」line32一定要判断父节点非空才可以使用父节点 ->next,因为并不是所有的节点都有父节点,如树的根节点

「4」在程序运行中,不要修改输入参数pNode,创建新的变量。如 currentNode 、parantNode 等。

 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)
    {
       if(pNode == nullptr){
            return nullptr;
        }
        TreeLinkNode* next = nullptr;
        //先右子节点的左子节点遍历
        if(pNode->right != nullptr){
            TreeLinkNode* rightNode  = pNode->right;
            while(rightNode->left != nullptr){
                rightNode = rightNode->left;
            }
            next = rightNode;
        }
            //向父结点遍历
        else if(pNode->next != nullptr){ //一定要判断父节点是否非空
            TreeLinkNode* parentNode = pNode->next;
            TreeLinkNode* currentNode = pNode;
            //当前节点是左节点时,不进入while循环。右节点进入循环
            //一定要判断父节点是否非空
            while(parentNode != nullptr  && currentNode == parentNode->right){
                currentNode = parentNode;
                parentNode = parentNode->next;
            }
            next = parentNode;
        }
        return next;
    }
};

基础知识:

 [1] NULL是0,nullptr是空指针void

https://blog.csdn.net/jays_/article/details/82586699 

 [2] 对变量的命名,要有意义。如父节点 parentNode,不要随便写pp、pc这种名字。

原文地址:https://www.cnblogs.com/GuoXinxin/p/10400544.html