题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向
我的想法很简单,分解&递归。从下至上构造,将其化为有序链表。构造过程中,若节点有右孩子,则左旋(或右旋),将右(左)孩子作为父节点的新左孩子,最后父节点连接左右子树(因左子树所有数大小都小于右子树任意节点,所以父节点必然在中间),作为新的左(右)孩子。
我以下面的树做例子讲下思路。
第一次分解
首先判断root是否是NULL,不为NULL,则递归分解。
递归的结果会将其分解为两个子树:
第二次分解
仍然不是叶子节点,继续分解
分解后发现1、3为叶子节点,从下往上进行构造链表。
因为其父节点有左儿子,所以需要进行节点更换,将第一次分解后的树变为如下结构:
1为新的根节点。
同样方法处理右子树。
得到右子树如下:
整体结构:
将4按照同样方法来进行处理,令左儿子作为新的根节点,将原根节点接在3的后面,同时连接到5上。
这样1 -> 2 ->3 ->4 ->5 这样的链表就构造完成了。
代码
这个代码我是按照左移数值增大这么写的,但牛客网要求右移增大,所以在代码的最后我遍历翻转了下指针以达到要求:
class Solution {
public:
TreeNode* Convert(TreeNode* pRootOfTree)
{
static int Counter = 0;Counter ++;//(1)
TreeNode* pRet = pRootOfTree;
if(pRootOfTree != NULL)
{
TreeNode* pLeft = Convert(pRootOfTree->left);//返回最小值节点
TreeNode* pRight = Convert(pRootOfTree->right);//返回最小值节点
if(pLeft != NULL)//需要更换返回的Root节点
{
pRet = pLeft;
while(pLeft->left)
{
pLeft = pLeft->left;
}
pLeft->left = pRootOfTree;
if(pRight)
pRight->right = pRootOfTree;
pRootOfTree->left = pRight;
pRootOfTree->right = pLeft;
}
else if(pRight != NULL)
{
pRet->left = pRight;
pRight->right = pRet;
}
pRet->right = NULL;
}
Counter--;//(2)
if(Counter == 0)//(1),(2),包括此处为翻转左右子树指针
{
TreeNode* pCurr = pRet;
while(pCurr)
{
TreeNode* pTemp = pCurr->left;
pCurr->left = pCurr->right;
pCurr->right = pTemp;
pCurr = pCurr->right;
}
}
return pRet;
}
};