面试题36:二叉搜索树与双向链表
题目描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
二叉树节点的定义如下:
public class Node {
int val = 0;
Node left = null;
Node right = null;
public Node(int val) {
this.val = val;
}
}
比如,输入下图的二叉搜索树,则输出转换之后的排序双向链表。
问题分析
二叉搜索树中序遍历的结果是排序的。
问题的解答一下子就明朗了,中序遍历先处理左子树,再处理根结点,之后处理右子树。在处理时,我们构建双向链表。
整个思路的大致流程:假设左子树处理完了,就要处理根结点,而根结点必须知道左子树的最大结点,所以要用函数返回值记录下来;之后处理右子树,右子树的最小结点(也用中序遍历得到)要和根结点链接。
问题解答
(1)递归写法
public Node Convert(Node root) {
if (root == null) {
return root;
}
// 处理左子树,获得左子树链表的头结点
Node left = Convert(root.left);
Node p = left;
if (left != null) {
// 找到左子树链表的末尾结点
while (p.right != null) {
p = p.right;
}
// 连接结点
p.right = root;
root.left = p;
}
// 处理右子树,获得右子树链表的头结点
Node right = Convert(root.right);
// 连接结点
if (right != null) {
root.right = right;
right.left = root;
}
return left == null ? root : left;
}
(2)非递归写法
利用非递归中序遍历来连接结点
public Node Convert(Node root) {
Node head = null;
Node pre = null;
LinkedList<Node> stack = new LinkedList<>();
while (root != null || !stack.isEmpty()) {
// 把root当作引用使用
while (root != null) {
stack.push(root);
root = root.left;
}
Node node = stack.pop();
if (head == null) {
head = node;
pre = node;
} else {
node.left = pre;
pre.right = node;
pre = node; // 别漏写了
}
root = node.right;
}
return head;
}