算法学习 day6--二叉搜索树与双向链表


本题代码已上传到: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 

空树
从左向右:

从右向左:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值