Java 二叉查找树转化为排序的循环双链表

算法与数据结构 专栏收录该内容
5 篇文章 0 订阅

Java 二叉查找树转化为排序的循环双链表


题目:
输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。
要求不能创建任何新的结点,只调整指针的指向。

例如对于下面的二分查找树:

ordered binary tree

small pointer 其实也就是指向左孩子,large pointer指向右孩子,转化为双链表之后 small pointer应该指向前一个元素,large pointer应该指向后一个元素。转化为排序的循环双链表则为:

circular doubly linked list

分析

二分查找树的中序遍历即为升序排列,问题就在于如何在遍历的时候更改指针的指向。一种简单的方法时,遍历二分查找树,讲遍历的结果放在一个数组中,之后再把该数组转化为双链表。如果题目要求只能使用O(1)内存,则只能在遍历的同时构建双链表,即进行指针的替换:

tree changed to list 2

我们需要用递归的方法来解决,假定每个递归调用都会返回构建好的双链表,可把问题分解为左右两个子树。

由于左右子树都已经是有序的,当前节点作为中间的一个节点,把左右子树得到的链表连接起来即可。


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);
   }
}

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

water123li

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值