本题代码已上传到:gitbub
题目
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。比如输入下图中左边的二叉搜索树,则输出右边转换之后的排序双向链表。
题目解析
ps:看到这道题目,最先应该相到的是中序遍历(如果没有请面壁)。
二叉搜索树是一种有序的二叉树,而中序遍历是按照左中右顺序访问树节点的遍历方式。二叉树节点中有指向左/右子节点的引用,而双向链表中有指向前/后的引用,实际上二叉树节点和双向链表节点是非常相识的。那么我们需要做的就是按照中序遍历的方式遍历二叉树,把二叉树节点当成双向链表节点,在遍历的过程中修改左右引用的指向的节点即可。
但是在编写的过程中我发现,使用中序遍历时,虽然能按顺序遍历到每个节点,但是无法在每个节点间跳跃。比如遍历到节点8时,需要将8的右引用改成节点10,而由于节点8的父节点是节点6,与节点10中间还隔了一层,因此他们是无法直接对接的。那么就需要有某种方法来将8和10关联起来。然而我想不到呀,只好看书了。
一看书就豁然开朗了,原来还差一个临时的节点引用,这个临时引用,指向当前链表的遍历位置,这样就能实现跳跃,将8和10关联起来了。比如最开始临时引用是null,按中序遍历我们需要最先处理4,这时临时引用指向4,然后处理6,那么临时引用指向6,然后处理8指向8,以此类推。
最后,由于java里面都是值传递,不像c++那样能传递引用,所以我们需要使用return的方式返回临时节点。
核心代码实现
/**
* 将二叉搜索树转成双向链表
* @param root 二叉树
* @return 双向链表
*/
private static BinaryTreeNode convertBST(BinaryTreeNode root) {
if(root == null){
return null;
}
BinaryTreeNode binaryTreeNode = convertBST(root, null);
while (binaryTreeNode.left != null) {
binaryTreeNode = binaryTreeNode.left;
}
return binaryTreeNode;
}
/**
* 将二叉搜索树转成双向链表
* @param node 二叉树节点
* @param tmp 临时节点
* @return 临时节点
*/
private static BinaryTreeNode convertBST(BinaryTreeNode node, BinaryTreeNode tmp) {
if (node == null) {
return null;
}
if (node.left != null) {
tmp = convertBST(node.left, tmp);
}
node.left = tmp;
if (tmp != null) {
tmp.right = node;
}
tmp = node;
if (node.right != null) {
tmp = convertBST(node.right, tmp);
}
return tmp;
}
测试用例
public static void main(String[] args) {
test("普通二叉树", getTree());
test("只有左节点的二叉树", getTree2());
test("只有右节点的二叉树", getTree3());
test("只有一个节点的二叉树", new BinaryTreeNode(1));
test("空树", null);
}
private static BinaryTreeNode getTree() {
BinaryTreeNode node = new BinaryTreeNode(10);
BinaryTreeNode node1l = new BinaryTreeNode(6);
BinaryTreeNode node1r = new BinaryTreeNode(14);
BinaryTreeNode node2ll = new BinaryTreeNode(4);
BinaryTreeNode node2lr = new BinaryTreeNode(8);
BinaryTreeNode node2rl = new BinaryTreeNode(12);
BinaryTreeNode node2rr = new BinaryTreeNode(16);
node.left = node1l;
node.right = node1r;
node1l.left = node2ll;
node1l.right = node2lr;
node1r.left = node2rl;
node1r.right = node2rr;
return node;
}
private static BinaryTreeNode getTree2() {
BinaryTreeNode node = new BinaryTreeNode(5);
BinaryTreeNode node1 = new BinaryTreeNode(4);
BinaryTreeNode node2 = new BinaryTreeNode(3);
BinaryTreeNode node3 = new BinaryTreeNode(2);
BinaryTreeNode node4 = new BinaryTreeNode(1);
BinaryTreeNode node5 = new BinaryTreeNode(0);
node.left = node1;
node1.left = node2;
node2.left = node3;
node3.left = node4;
node4.left = node5;
return node;
}
private static BinaryTreeNode getTree3() {
BinaryTreeNode node = new BinaryTreeNode(1);
BinaryTreeNode node1 = new BinaryTreeNode(2);
BinaryTreeNode node2 = new BinaryTreeNode(3);
BinaryTreeNode node3 = new BinaryTreeNode(4);
BinaryTreeNode node4 = new BinaryTreeNode(5);
BinaryTreeNode node5 = new BinaryTreeNode(6);
node.right = node1;
node1.right = node2;
node2.right = node3;
node3.right = node4;
node4.right = node5;
return node;
}
private static void test(String test, BinaryTreeNode root) {
System.out.println(test);
BinaryTreeNode binaryTreeNode = convertBST(root);
System.out.println("从左向右:");
while (binaryTreeNode != null) {
System.out.print(binaryTreeNode.val + " ");
if (binaryTreeNode.right == null) {
break;
}
binaryTreeNode = binaryTreeNode.right;
}
System.out.println();
System.out.println("从右向左:");
while (binaryTreeNode != null) {
System.out.print(binaryTreeNode.val + " ");
if(binaryTreeNode.left == null){
break;
}
binaryTreeNode = binaryTreeNode.left;
}
System.out.println();
System.out.println();
}
测试结果
普通二叉树
从左向右:
4 6 8 10 12 14 16
从右向左:
16 14 12 10 8 6 4
只有左节点的二叉树
从左向右:
0 1 2 3 4 5
从右向左:
5 4 3 2 1 0
只有右节点的二叉树
从左向右:
1 2 3 4 5 6
从右向左:
6 5 4 3 2 1
只有一个节点的二叉树
从左向右:
1
从右向左:
1
空树
从左向右:
从右向左: