描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。如下图所示
数据范围:输入二叉树的节点数 0≤n≤1000,二叉树中每个节点的值 10000≤val≤1000 要求:空间复杂O(1)(即在原树上操作),时间复杂度 O*(*n)
注意:
1.要求不能创建任何新的结点,只能调整树中结点指针的指向。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继 2.返回链表中的第一个节点的指针 3.函数返回的TreeNode,有左右指针,其实可以看成一个双向链表的数据结构
4.你不用输出双向链表,程序会根据你的返回值自动打印输出
输入描述:
二叉树的根节点
返回值描述:
双向链表的其中一个头节点。
示例1
输入:
{10,6,14,4,8,12,16}
返回值:
From left to right are:4,6,8,10,12,14,16;From right to left are:16,14,12,10,8,6,4;
说明:
输入题面图中二叉树,输出的时候将双向链表的头节点返回即可。 示例2
输入:{5,4,#,3,#,2,#,1}
返回值:
From left to right are:1,2,3,4,5;From right to left are:5,4,3,2,1;
说明:
5
/
4
/
3
/
2
/
1
树的形状如上图思路:
这里将二叉树的 left 作为前驱节点,right 作为后驱节点,相当于双向链表中的 prev 和 next。
而这里比较难搞的就是如何在递归的同时去链接两个节点,所以这里我们得传两个参数才行,一个是当前节点 root,另一个是上一个走过的节点 prev。
然后用中序遍历,先遍历到最深的左子树(因为这是二叉搜索树的性质),接着开始链接:
- 先让 root 的 left 指向 prev,也就是完成前驱节点的链接
- 然后让 prev 的 right 指向 root,也就是完成后驱节点的链接(不能用 root 来完成后驱节点链接,因为 root 在这里不知道它的下一个节点是哪一个,但是我们知道的是 prev 的下一个节点是指向 root 的)
- 最后让 prev 移到 root 的位置,作为下一次递归的前一个节点
- 注意这里 prev 要传引用接收,因为我们要的就是要让 prev 的链接影响到上一次和下一次的链接,也就是希望它只是唯一的 prev,所以要传引用!
将链接完成后,我们发现 pRootOfTree 就在链表的中间,所以我们最后让它移到链表的头部,最后返回 pRootOfTree 即可。
class Solution {
public:
//这里prev要传引用,因为我们希望全局只改变一个prev
void link(TreeNode* root, TreeNode*& prev)
{
if(root == nullptr)
return;
link(root->left, prev);
//先让后面节点的左链接到前面节点
root->left = prev;
//让前面节点的右链接到后面节点
if(prev)
prev->right = root;
//最后让prev变到root处,作为下一次递归的前一个节点
prev = root;
link(root->right, prev);
}
TreeNode* Convert(TreeNode* pRootOfTree)
{
//判断一下为空的情况
if(pRootOfTree == nullptr)
return nullptr;
TreeNode* prev = nullptr;
link(pRootOfTree, prev);
//链接完后pRootOfTree是中间节点,所以让它回到头节点
while(pRootOfTree->left != nullptr)
{
pRootOfTree = pRootOfTree->left;
}
return pRootOfTree;
}
};