1. 程式人生 > >08 二叉樹的下一個節點

08 二叉樹的下一個節點

初始 tro src 是否 ref -- tps info left

題目描述:

給定一個二叉樹和其中的一個節點,請找出中序遍歷順序的下一個節點並且返回。註意,樹中的節點不僅包含左右子節點(指向左右子節點的指針),同時包含指向父節點的指針。

測試用例:

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這種名字。

08 二叉樹的下一個節點