题目描述:
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
分析:
按照题目要求,我们将题中给的二叉树变为双向链表,由于所给的二叉树是一棵二叉搜索树,所以我们根据节点值的大小来改变指向,如下图所示:
因此,整体的思路就是通过中序遍历来改变每个节点的左右指针域,具体题解步骤如下:
树为空
:直接返回root树不为空
:改变每个节点的指向(中序遍历
)- 通过中序遍历先做到最左下角节点,然后从最左下节点开始改变指向:让其(cur)left指向pre;pre的后继(right)指向cur.
- 接着通过递归改变左子树的指向
- 通过递归改变右子树的指向。
注意:
- 题目要求最后返回head,这个head是链表中的第一个节点的指针,也就是上图中的节点1,`因此我们还需要让节点1的前驱指向最后一个节点(节点5),让最后一个节点的后继指向第一个节点,这就需要在中序遍历之后将第一个节点和最后一个节点保存起来,然后改变它两的前驱和后继。
- 由于一开始我们没办法让第一个节点的前驱指向最后一个节点,我们只能先令pre=null
代码:
class Solution {
Node pre=null;
//中序遍历改变指向
public void changePtr(Node cur)
{
if(cur==null)
{
return;
}
//先改变左子树
changePtr(cur.left);
cur.left=pre;//当前节点前驱指向pre
if(pre!=null)
{pre.right=cur;}//pre的后继指向当前节点
pre=cur;//更新pre
//再改变右子树
changePtr(cur.right);
}
public Node treeToDoublyList(Node root) {
if(root == null)
{
return root;
}
//改变指向
changePtr(root);
//找到第一个节点保存到head中
Node head=root;
while(head!=null)
{
head=head.left;
}
//找到最后一个节点保存到last中
Node last=root;
while(last!=null)
{
last=last.right;
}
//改变第一个前驱和最后一个的后继
head.left=last;
last.right=head;
return head;
}
}