剑指 Offer 36. 二叉搜索树与双向链表
题目:
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
解题思路:
比较容易能够想到,二叉搜索树的中序遍历就是排好序的结果,然后自己在求解的时候考虑了引入额外对的数据结构,按照中序遍历的顺序存下经过的树节点,然后在遍历保存的中序序列结果,修改left和right的指向,即当前节点的 left 指向上一个节点,right 节点指向下一个节点,最后让第一个节点的 left 指向最后一个节点,最后一个节点的 right 指向第一个节点
java实现-使用辅助空间:
//借助辅助数据结构
public static LinkedList<Node> list;
public static void dfs(Node root){
if(root==null) return;
dfs(root.left);
list.add(root);
dfs(root.right);
}
public Node treeToDoublyList(Node root) {
if(root==null) return root;
list = new LinkedList<Node>();
dfs(root);
int size = list.size();
for(int i=0;i<size;i++){
// System.out.print(list.get(i).val+" ");
if(i+1<size) list.get(i).right = list.get(i+1);
if(i-1>=0) list.get(i).left = list.get(i-1);
}
list.get(0).left = list.get(size-1);
list.get(size-1).right = list.get(0);
return list.get(0);
}
之后查看别人的解法,同样是在中序遍历的基础上,增加一个 pre 和 head 节点,让当前遍历到的节点为 cur 的时候,pre 节点保存指向中序遍历顺序的节点 cur 的前一个节点,head 节点保存头结点,那么当中序遍历的时候即有 pre.right=cur,cur.left=pre.当中序遍历结束之后此时的 head 节点记录头部,pre 节点指向的是尾部,然后设置 head.left=pre,pre.right=head
算法流程:
1.终止条件: 当节点cur为空的时候,表示越过叶子节点,直接放回
2.递归左子树.
3.构建链表:
(1)当pre
为空的时候,代表此时访问的是第一个节点,记为head.
(2)当pre
不为空的时候,修改双向链表的指向,即pre.right = cur, cur.left = pre
(3)保存cur
:更新pre = cur
4.递归右子树
5.构建头尾指针的指向,即head.left = pre,pre.right = head.
java实现-pre指针:
public Node head, pre;
public void buildList(Node root){
if(root==null) return;
buildList(root.left);
if(pre!=null) pre.right = root; //是中序遍历序列意义上的pre
else head = root;
root.left = pre;
pre = root;
buildList(root.right);
}
public Node treeToDoublyList(Node root) {
if(root==null) return null;
//先构建双向链表,最后增加头尾
buildList(root);
//最后一定是head到头结点,pre到尾节点
head.left = pre;
pre.right = head;
return head;
}