Java 二叉查找树转化为排序的循环双链表
题目:
输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。
要求不能创建任何新的结点,只调整指针的指向。
例如对于下面的二分查找树:
small pointer 其实也就是指向左孩子,large pointer指向右孩子,转化为双链表之后 small pointer应该指向前一个元素,large pointer应该指向后一个元素。转化为排序的循环双链表则为:
分析
二分查找树的中序遍历即为升序排列,问题就在于如何在遍历的时候更改指针的指向。一种简单的方法时,遍历二分查找树,讲遍历的结果放在一个数组中,之后再把该数组转化为双链表。如果题目要求只能使用O(1)内存,则只能在遍历的同时构建双链表,即进行指针的替换:
我们需要用递归的方法来解决,假定每个递归调用都会返回构建好的双链表,可把问题分解为左右两个子树。
由于左右子树都已经是有序的,当前节点作为中间的一个节点,把左右子树得到的链表连接起来即可。
1 自己写的可运行的完整代码:
package cn.sjtu.practice.test3;
public class Solution33 {
/**
* 二叉树转双向链表
* @param root
* @return
*/
static TreeNode treeToList(TreeNode root) {
if (root == null) {
return null;
}
// 递归解决子树
TreeNode leftHead = treeToList(root.left);
TreeNode rightHead = treeToList(root.right);
// 把根节点转换为一个节点的双链表。方便后面的链表合并
root.left = root;
root.right = root;
if (leftHead != null) {
TreeNode leftTail = leftHead.left;
leftTail.right = root;
root.left = leftTail;
leftHead.left = root;
root.right = leftHead;
} else {
leftHead = root;
}
if (rightHead != null) {
TreeNode rightTail = rightHead.left;
root.right = rightHead;
rightHead.left = root;
// 首尾相接
leftHead.left = rightTail;
rightTail.right = leftHead;
}
return leftHead;
}
public static void main(String[] args) {
TreeNode root = new TreeNode(5, new TreeNode(3, new TreeNode(1), new TreeNode(4)),
new TreeNode(7, null, new TreeNode(9)));
inOrderTraverse(root);
System.out.println();
TreeNode treeToList = treeToList(root);
show(treeToList);
}
public static void show(TreeNode head) {
TreeNode tempHead = head;
while (head != null) {
System.out.print(head.val + " ");
head = head.right;
if (head == tempHead) {
break;
}
}
System.out.println();
}
/**
* 中序遍历
*
* 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已
*
* @param node
* 遍历的节点
*/
public static void inOrderTraverse(TreeNode node) {
if (node == null)
return;
inOrderTraverse(node.left);
System.out.print(node.val + " ");
inOrderTraverse(node.right);
}
}
2 程序2
package nowcoder.test1;
public class Convert {
public static TreeNode convert(TreeNode pRootOfTree) {
if (pRootOfTree == null) {
return null;
}
if (pRootOfTree.left == null && pRootOfTree.right == null) {
return pRootOfTree;
}
// 1.将左子树构造成双链表,并返回链表头节点
TreeNode left = convert(pRootOfTree.left);
TreeNode p = left;
// 2.定位至左子树双链表最后一个节点
while (p != null && p.right != null) {
p = p.right;
}
// 3.如果左子树链表不为空的话,将当前root追加到左子树链表
if (left != null) {
p.right = pRootOfTree;
pRootOfTree.left = p;
}
// 4.将右子树构造成双链表,并返回链表头节点
TreeNode right = convert(pRootOfTree.right);
// 5.如果右子树链表不为空的话,将该链表追加到root节点之后
if (right != null) {
right.left = pRootOfTree;
pRootOfTree.right = right;
}
return left != null ? left : pRootOfTree;
}
public static void main(String[] args) {
TreeNode root = new TreeNode(5, new TreeNode(3, new TreeNode(1), new TreeNode(4)),
new TreeNode(7, null, new TreeNode(9)));
inOrderTraverse(root);
System.out.println();
TreeNode treeToList = convert(root);
show(treeToList);
}
public static void show(TreeNode head) {
TreeNode tempHead = head;
while (head != null) {
System.out.print(head.val + " ");
head = head.right;
if (head == tempHead) {
break;
}
}
System.out.println();
}
/**
* 中序遍历
*
* 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已
*
* @param node
* 遍历的节点
*/
public static void inOrderTraverse(TreeNode node) {
if (node == null)
return;
inOrderTraverse(node.left);
System.out.print(node.val + " ");
inOrderTraverse(node.right);
}
}
public class Convert {
public static TreeNode convert(TreeNode pRootOfTree) {
if (pRootOfTree == null) {
return null;
}
if (pRootOfTree.left == null && pRootOfTree.right == null) {
return pRootOfTree;
}
// 1.将左子树构造成双链表,并返回链表头节点
TreeNode left = convert(pRootOfTree.left);
TreeNode p = left;
// 2.定位至左子树双链表最后一个节点
while (p != null && p.right != null) {
p = p.right;
}
// 3.如果左子树链表不为空的话,将当前root追加到左子树链表
if (left != null) {
p.right = pRootOfTree;
pRootOfTree.left = p;
}
// 4.将右子树构造成双链表,并返回链表头节点
TreeNode right = convert(pRootOfTree.right);
// 5.如果右子树链表不为空的话,将该链表追加到root节点之后
if (right != null) {
right.left = pRootOfTree;
pRootOfTree.right = right;
}
return left != null ? left : pRootOfTree;
}
public static void main(String[] args) {
TreeNode root = new TreeNode(5, new TreeNode(3, new TreeNode(1), new TreeNode(4)),
new TreeNode(7, null, new TreeNode(9)));
inOrderTraverse(root);
System.out.println();
TreeNode treeToList = convert(root);
show(treeToList);
}
public static void show(TreeNode head) {
TreeNode tempHead = head;
while (head != null) {
System.out.print(head.val + " ");
head = head.right;
if (head == tempHead) {
break;
}
}
System.out.println();
}
/**
* 中序遍历
*
* 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已
*
* @param node
* 遍历的节点
*/
public static void inOrderTraverse(TreeNode node) {
if (node == null)
return;
inOrderTraverse(node.left);
System.out.print(node.val + " ");
inOrderTraverse(node.right);
}
}