24 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表

一、题目
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
二、解题思路
在这里插入图片描述
调整指针

原先指向左子节点的指针调整为链表中指向前一个节点的指针

原先指向右子节点的指针调整为链表中指向后一个节点的指针

如何调整

考虑根节点和左右子树的根本情况,因为如果用递归,这种根本情况考虑就可以去将同样的方法用到左右子树上

在这里插入图片描述

对于这种基本情况,可以分成三个部分来看,根节点10,左子树,右子树,需要做的就是将10与左子树中的最大值连起来,然后把10与右子树中的最小值连起来

现在有个问题就是我们并不知道左子树中的最大值和右子树中的最小值,如果我们知道就好了。但是想到递归,递归到左子树中,如果左子树已转换为双向链表,那么双向链表的最后一个节点就是我们想要的,而右子树中的第一个节点也是我们想要的

上面的代码中有两个参数,一个是根节点,一个是已经转换好的链表的最后一个节点,因为二叉搜索树中序遍历的特性,当遍历到根节点的时候,左子树已经排好序了,所以会有一个左子树已经转换好的链表,而这个链表的最后一个节点即是我们需要和根节点左连的节点
在这里插入图片描述
最开始的时候lastNode为null

current为当前子树的根节点

如果左子树存在,那么转换左子树,递归下去,递归返回之后,说明找到了链表的第一个节点,也就是4那个节点,将4的前面节点置为null,此时current为4那个节点,这个时候由于6的4这个左子树已遍历完了,所以需要往上层返回,返回之前需要将current赋值给lastNode,说明4这个左子树的最后一个节点就是4

由于往上返回了一层,此时的current已经是6了,将6的左节点赋值为之前返回的4,判断之前返回的lastNode是否为null,不为空说明需要把根节点和lastNode连起来,其实lastNode为null的情况就只有第一个节点会出现,其他的时候都不会出现。现在已排好序的包括6的左子树以及6本身了,所以此时的lastNode为6

6和4的双向连接就完成了,由于6的右子树存在,又会递归到右边子树去,由于8不存在左右子树,递归下去一层之后current就是8这个节点,但它的左孩子为空,所以不会左边递归下去,将8的左连接与之前的lastNode连接起来,建立双向连接的一条连接,然后由于lastNode不为空,所以又把lastNode的右连接与8连接起来,至此双向连接建立,此时lastNode为8

所以468都已排好序,此时lastNode为8,返回到上一层,也就是根节点10了,在这一层current为10,将current的左连接与lastNode连接起来,如果lastNode存在,将lastNode的右连接与10连接一起,以此建立双向连接。至此就将根节点和左子树都连接起来了,然后就是去转换右子树,现在的lastNode为10,current为14,14有左孩子,所以需要递归到下一层,下一层的current为12,12没有左孩子,所以不用在坐递归,所以12是12这棵子树转换成双向链表的最左边的节点,将lastNode与12连接,也就是10与12连接,此时的lastNode就变成了12,再将12的右子树递归,由于没有右子树,所以直接返回到上一层,上一层的current是14,14与已排好序的lastNode连接,也就是12与14连接,然后lastNode变为14,递归到14的右子树,也就current变为16,16再递归左子树,无左子树,将16与14连接,此时的lastNode变为16,递归右子树,无右子树,所以整个递归工作完成

  public static class BinaryTreeNode {
        int value;
        BinaryTreeNode left;
        BinaryTreeNode right;

        public BinaryTreeNode(int value) {
            this.value = value;
        }
    }
	/**
     * 主函数
     *
     * @param args
     */
    public static void main(String[] args) {

        /**  二叉查找树转双向链表
         * //                 10
         *     //         /      \
         *     //        6        14
         *     //       /\        /\
         *     //      4  8     12  16**/
        BinaryTreeNode root = new BinaryTreeNode(10);

        BinaryTreeNode six = new BinaryTreeNode(6);

        BinaryTreeNode four = new BinaryTreeNode(4);

        BinaryTreeNode eight = new BinaryTreeNode(8);

        BinaryTreeNode fourteen = new BinaryTreeNode(14);

        BinaryTreeNode twelve = new BinaryTreeNode(12);

        BinaryTreeNode sixteen = new BinaryTreeNode(16);

        root.left = six;

        root.right = fourteen;

        six.left = four;

        six.right = eight;

        four.left = null;

        four.right = null;

        eight.left = null;

        eight.right = null;

        fourteen.left = twelve;

        fourteen.right = sixteen;

        twelve.left = null;

        twelve.right = null;

        sixteen.right = null;

        sixteen.left = null;

        BinaryTreeNode result = convert(root);

        while (result != null) {

            System.out.println("我是结果====" + result.value);

            result = result.right;

        }


    }

    /**
     * @param root 根节点
     * @return
     */
    public static BinaryTreeNode convert(BinaryTreeNode root) {//10

        BinaryTreeNode lastNode = null;

        lastNode = baseconvert(root, lastNode);//10,null

        BinaryTreeNode headNode = lastNode;

		 // 找到双向链表的头结点,(返回的lastNode是最后节点16,倒叙)
        while (headNode.left != null)

            headNode = headNode.left;

        return headNode;

    }

    /**
     * @param root     根节点
     * @param lastNode 已经转换好的链表的最后一个节点
     * @return * //                       10
     * *     //         /      \
     * *     //        6        14
     * *     //       /\        /\
     * *     //      4  8     12  16
     * <p>
     * 4--6---8
     **/


    public static BinaryTreeNode baseconvert(BinaryTreeNode root, BinaryTreeNode lastNode) {
         if (root == null)

            return lastNode;

        BinaryTreeNode current = root;
	     // 如果有左子树就先处理左子树
        if (current.left != null) {
            lastNode = baseconvert(current.left, lastNode);   
           }
		// 将当前结点的前驱指向已经处理好的双向链表(由当前结点的左子树构成)的尾结点
        current.left = lastNode;
      // 设置尾结点的后继,  比如(lastNode) 4<----->6(current) 双指向
        if (lastNode != null) {
            lastNode.right = current; 
        }
	  // 记录当前结点为尾结点
          lastNode = current;
	 	// 处理右子树
        if (current.right != null) {
            lastNode = baseconvert(current.right, lastNode);
        }

        return lastNode;

    }

打印结果
我是结果====4
我是结果====6
我是结果====8
我是结果====10
我是结果====12
我是结果====14
我是结果====16
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值