題目描述:有一個搜索二叉樹,對於樹中的任意一個節點,其左子樹的所有值小於該節點的值,而其右子樹的所有值大於該節點的值。要求:在不定義任何新的節點情況下,將該二叉樹轉換成為一個排序雙向鏈表。
假設有上面的二叉樹,那么其轉換為雙向鏈表后的順序應該為:2 3 4 5 6 7 8
對於鏈表頭節點:其直接前驅為空指針,直接后繼為其父節點;
對於鏈表尾節點:其直接前驅為其父節點,直接后繼為空;
對於左子樹的根節點:其直接前驅為其左子樹中的最大值;其直接后繼為其右子樹中的最小值或者父節點的值;
對於右子樹的根節點:其直接前驅為其左子樹中的最大值或者父節點的值;其直接后繼為右子樹中的最大值;
因此,我們可以將二叉樹看作三個部分:根節點、左子樹、右子樹。
如果我們可以遞歸地將左子樹和右子樹轉換成為排序的雙向鏈表,那么整個二叉樹也就被轉換成了排序的雙向鏈表。
示例代碼如下:
#include<iostream>
using namespace std; struct BinTreeNode { int value; BinTreeNode *LeftNode; BinTreeNode *RightNode; }; void ConvertNode(BinTreeNode *pNode, BinTreeNode **pLastNodeInList); BinTreeNode *Convert(BinTreeNode *pRootNode) { BinTreeNode *pLastNodeInList = nullptr; ConvertNode(pRootNode, &pLastNodeInList); BinTreeNode *pHeadOfList = pLastNodeInList; //此時pHeadOfList是二叉樹的頭節點,要返回鏈表頭需要將它向左移,直到到達鏈表頭
while (pHeadOfList != nullptr&&pHeadOfList->LeftNode != nullptr) { pHeadOfList = pHeadOfList->LeftNode; } //返回鏈表的頭節點
return pHeadOfList; } void ConvertNode(BinTreeNode *pNode, BinTreeNode **pLastNodeInList) { if (pNode == nullptr) { return; } BinTreeNode *pCurrentNode = pNode; //如果存在左子樹,那么遞歸地修改左子樹節點指向
if (pCurrentNode->LeftNode != nullptr){ ConvertNode(pNode->LeftNode, pLastNodeInList);} //將當前節點的左子節點指向鏈表尾部元素(因為鏈表尾部元素更小)
pCurrentNode->LeftNode = *pLastNodeInList; //將鏈表尾部元素的右子節點指向當前節點,與上一步操作類似;
if (*pLastNodeInList != nullptr){ (*pLastNodeInList)->RightNode = pCurrentNode; } //更新鏈表尾部元素
*pLastNodeInList = pCurrentNode; //遞歸的修改右子樹的節點指向
if (pCurrentNode->RightNode != nullptr) { ConvertNode(pCurrentNode->RightNode, pLastNodeInList); } } int main() {}
將上述代碼對上面圖示的二叉樹進行轉換,其轉換過程中的變量變化如下,這能幫助我們理解整個轉換的過程:
在Convert函數中調用ConvertNode()函數結束以后,用來存儲鏈表尾部元素的變量值為二叉樹的根節點的值,即:10。
因此,為了正確地返回鏈表頭部元素,需要將該指針向左移到鏈表頭地位置,最終將這個指針返回。