美文网首页
二叉搜索树与双向链表

二叉搜索树与双向链表

作者: 囧略囧 | 来源:发表于2018-10-27 13:27 被阅读0次

    题目描述

    输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

    二叉搜索树的定义:

    二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

    所要求的为排序列表,根据二叉搜索树的定义我们可以知道,二叉搜索树的中序遍历便是有序的。所以我们可以中序遍历二叉树。

    image

    解法一:

    通过递归不断地将节点与其排序好的左右子树连接

    public class Solution {
        public TreeNode Convert(TreeNode pRootOfTree) {
            if(pRootOfTree == null) {
                return null;
            }
            TreeNode res = ConvertCore(pRootOfTree);
            while(res.left != null) {
                res = res.left;
            }
            return res;
        }
        public TreeNode ConvertCore(TreeNode pRootOfTree) {
            if(pRootOfTree == null) {
                return null;
            }
            //获得排序好的左子树
            TreeNode left = ConvertCore(pRootOfTree.left);
            if(left != null) {
                //获得左子树的最右节点
                while(left.right != null) {
                    left = left.right;
                }
                //将排序好的左子树与根节点连接
                left.right = pRootOfTree;
                pRootOfTree.left = left;
            }
            //获得排序好的右子树
            TreeNode right = ConvertCore(pRootOfTree.right);
            if(right != null) {
                //获得右子树的最左节点
                while (right.left != null) {
                    right = right.left;
                }
                //将排序好的右子树与根节点连接
                pRootOfTree.right = right;
                right.left = pRootOfTree;
            }
            return pRootOfTree;
        }
    }
    

    解法二:

    解法一中要不断地靠循环来确定左右子树的最右和最左节点,时间效率较低。我们知道,中序遍历过程是有序的,我们可以使用一个指针保存当前中序遍历的点,依次将中序遍历经过的点连接起来便可以得到有序的双向链表,省去了大量的循环操作。

    public class Solution {
        TreeNode current = null;
        public TreeNode Convert(TreeNode pRootOfTree) {
            if(pRootOfTree == null) {
                return null;
            }
            ConvertCore(pRootOfTree);
            while(current.left != null) {
                current = current.left;
            }
            return current;
        }
        public void ConvertCore(TreeNode pRootOfTree) {
            if(pRootOfTree == null) {
                return ;
            }
            ConvertCore(pRootOfTree.left);
            //记录二叉搜索树中最左边的节点即最小节点
            if(current == null) {
                current = pRootOfTree;
            }
            //连入新节点并更新双向链表的最右节点
            else{
                current.right = pRootOfTree;
                pRootOfTree.left = current;
                current = pRootOfTree;
            }
            ConvertCore(pRootOfTree.right);
        }
    }
    

    在上面的代码中,使用current来记录已经转换好的链表的最后一个节点。 例如当前节点为10的时候,current为8,将10与8连接后,current更新为10。接着遍历右子树,右子树的第一个点为12,将10和12连接起来,current更新为12。以此类推。

    解法三:

    解法二中用一个current保存中序遍历经过的节点,在最后返回时仍需要通过循环从current获得初始节点,我们如果再用一个指针来保存初始节点,便可以免去 这个循环操作,在数据量较大时节省一部分时间。

    public class Solution {
        //双向链表的头节点
        TreeNode left = null;
        //中序遍历中依次经过的点,相当于解法二的current
        TreeNode right = null;
        public TreeNode Convert(TreeNode pRootOfTree) {
            if(pRootOfTree == null) {
                return null;
            }
            Convert(pRootOfTree.left);
            //保存双向链表的头节点
            if(right == null) {
                left = pRootOfTree;
                right = pRootOfTree;
            }
            //中序遍历过程中进行连接,并更新已获得的双向链表的尾节点
            else {
                right.right = pRootOfTree;
                pRootOfTree.left = right;
                right = pRootOfTree;
            }
            Convert(pRootOfTree.right);
            return left;
        }
    }
    

    相关文章

      网友评论

          本文标题:二叉搜索树与双向链表

          本文链接:https://www.haomeiwen.com/subject/ryjktqtx.html