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這種名字。
08 二叉樹的下一個節點