剑指 Offer 36. 二叉搜索树与双向链表
问题描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
“head” 表示指向链表中有最小元素的节点。
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
解题思路
解法一(递归解法):
首先由于二叉搜索树本身就是有序的,因此转换为排序双向链表的时候,需要完成:把原本指向左节点的指针改变为指向上一节点,把原本指向右节点的指针改变为指向下一节点。
因为需要按照从小到大的顺序生成双向链表,基于二叉搜索树的性质,应该中序遍历。并在遍历的过程中依次改变左右指针。
当我们处理一个根节点时,说明我们已经处理完他的左子树了,并且已经生成了一个双向链表,链表的最后一个元素应该就作为当前根节点的left,并且双向的设置最后一个元素的right指针指向当前根节点。再遍历右子树。
可以发现,这个过程是重复的,所以使用递归的思路来解决会很方便。
中序遍历模板如下:
// 打印中序遍历
void dfs(Node root) {
if(root == null) return;
dfs(root.left); // 左
System.out.println(root.val); // 根
dfs(root.right); // 右
}
解法二(迭代解法):
既然是使用中序遍历,除了递归解法,肯定还有迭代解法。只需要按照上面的解题思路在迭代的模板中改动关键代码就可以。
//中序遍历迭代模板
public void inOrderTraversal(TreeNode tree) {
Stack<TreeNode> stack = new Stack<>();
while (tree != null || !stack.isEmpty()) {
while (tree != null) {
stack.push(tree);
tree = tree.left;
}
if (!stack.isEmpty()) {
tree = stack.pop();
System.out.println(tree.val);
tree = tree.right;
}
}
}
迭代解法即在上述迭代模板的基础上,增加改变left和right的代码。
Java代码
解法一(递归解法):
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val,Node _left,Node _right) {
val = _val;
left = _left;
right = _right;
}
};
*/
class Solution {
Node pre,head;
public Node treeToDoublyList(Node root) {
if(root==null) return root;
dfs(root);
head.left = pre;
pre.right = head;
return head;
}
public void dfs(Node cur){
if(cur==null) return;
dfs(cur.left);
if(pre!=null) pre.right = cur;
else head = cur;
cur.left = pre;
pre = cur;
dfs(cur.right);
}
}
解法二(迭代解法):
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val,Node _left,Node _right) {
val = _val;
left = _left;
right = _right;
}
};
*/
class Solution {
Node pre,head;
public Node treeToDoublyList(Node root) {
if(root==null) return root;
Stack<Node> st = new Stack<>();
Node head=null,pre=null;
Node cur = root;
while(!st.empty() || cur!=null){
while(cur!=null){
st.push(cur);
cur = cur.left;
}
if(!st.empty()){
cur = st.pop();
if(pre==null){
head = cur;
} else pre.right = cur;
cur.left = pre;
pre = cur;
cur = cur.right;
}
}
head.left = pre;
pre.right = head;
return head;
}
}