• 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这种名字。

  • 相关阅读:
    微信下载远程图片的公用方法
    微信接口调用
    微信
    post方法
    asp.net pagebase获取缓存的方法
    sql查询最大id
    Controller里写自己需要的Action,参数的名字必须和路由设置的参数名一致

    递归调用
    队列及其应用
  • 原文地址:https://www.cnblogs.com/GuoXinxin/p/10400544.html
Copyright © 2020-2023  润新知