剑指 Offer 36. 二叉搜索树与双向链表
难度中等619
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
思路
本题还是利用其二叉搜索树的特点,中序遍历的序列是递增有序的.,但是中间形成双向链表,确实不好想,但是看完题解之后瞬间清晰.
根据题意 : 将该二叉搜索树转换成一个排序的循环双向链表,也就是说头尾也得相连.
既然是利用二叉搜索树中序遍历,我之前总结过,需要一个prev前驱指针(也要根据当前节点与前驱结点有没有关系而决定).
具体步骤 :
- 使用中序遍历
- 记录prev前驱指针,head头结点,记住head千万不能每次都动,要不成死循环了,head一定是刚开始确定,后面就不能动了.
- 在cur不为空的情况下
- 前驱结点为null,意味着刚开始遍历,设置头结点
- 前驱结点不为null,意味着当前节点能够和前驱形成双向链表关系(prev的右孩子链上cur,cur的左孩子链上prev)
- 然后更新前驱结点--->进行迭代
- 中序遍历完成后,进行头结点head与尾结点prev进行相连,形成双向循环关系
class Solution {
private Node prev = null;
private Node head = null;
private void dfs(Node cur) {
if(cur==null) return;
//利用中序遍历的序列递增特点
dfs(cur.left);
if(prev==null) {//刚开始记录头结点
head = cur;
}else {//形成双向链表
prev.right = cur;
cur.left = prev;
}
//迭代记录节点前序
prev = cur;
dfs(cur.right);
}
public Node treeToDoublyList(Node root) {
if(root==null) return root;
dfs(root);
//头尾相连
head.left = prev;
prev.right = head;
//返回新头
return head;
}
}
使用 cur.left = prev ,prev.right = cur这样才能够利用其中序遍历,来帮助我们自然地形成形成双向链表.
还需要注意的是 : head一定在一开始就固定,否则成环,导致死循环,至于双向链表肯定和当前节点,前驱节点相关,要想形成关联,那就需要操作其左右指针,对于这种题二叉树转链表的,肯定是与前驱节点相关,下一步就要想操作其左指针还是操作其右指针,哪一个指针不动,就自然形成了链表.