• 二叉搜索树与双向排序链表的转换


    题目描述

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

    /**
    public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;
    
        public TreeNode(int val) {
            this.val = val;
    
        }
    
    }
    */
    public class Solution {
        public TreeNode Convert(TreeNode pRootOfTree) {
            
        }
    }
    

    思路分析

    image

    二叉搜索树如何与双向链表相关联呢?首先要了解二叉搜索树(BST)的性质,左节点<根节点<右节点

    而要满足这个顺序就需要对二叉树进行中序遍历,那么就是已经排好序的链表了

    image

    代码

    public class Test9 {
        public static class TreeNode {
            int val = 0;
            TreeNode left = null;
            TreeNode right = null;
    
            public TreeNode(int val) {
                this.val = val;
    
            }
    
        }
    
     /**
         * 定义:转换后left表示pre,right表示next
         * @param pRootOfTree  根结点
         * @return
         */
        public static TreeNode Convert(TreeNode  pRootOfTree) {
            if(pRootOfTree==null) return pRootOfTree;
            //链表尾节点
            TreeNode lastNode=null;
            //转换
            lastNode=convert(pRootOfTree,lastNode);
            //寻找返回的头结点
            TreeNode head=lastNode;
            while(head.left!=null) {
                head = head.left;
            }
    
            return head;
        }
    
        /**
         * 返回当前已转换好的链表的尾结点
         * @param root  当前子树的根结点
         * @param last  保存当前链表的最后一个指针
         * @return  返回当前链表的最后一个结点
         */
        public static TreeNode convert(TreeNode root,TreeNode last) {
            System.out.println("--------------------------进入convert方法-------------------------------");
            if(root==null) return null;
            TreeNode p=root;
            System.out.println("current root=>"+p.val);
            //转换左子树
            System.out.println("=========递归左子树=========");
            if(root.left!=null) last=convert(root.left,last);
            if(last != null){
    
                System.out.println("***************当前根节点***********"+p.val);
                System.out.println("当前列表的最后一个节点(当前左子树的最大节点)=>"+last.val);
            }else {
                System.out.println("***************当前根节点***********"+p.val);
                System.out.println("当前列表的最后一个节点(当前左子树的最大节点)=>"+null);
            }
            //根结点的pre指向左子树的last,左子树的last的next指向根结点
            p.left=last;
            if(last != null){
                System.out.println("***************当前根节点***********"+p.val);
                System.out.println("根结点的pre指向左子树的last=>"+last.val);
            }else {
                System.out.println("***************当前根节点***********"+p.val);
                System.out.println("根结点的pre指向左子树的last=>"+null);
            }
    
            if(last!=null) last.right=p;
            //last指向根结点
            last=p;
            if(last != null){
                System.out.println("***************当前根节点***********"+p.val);
                System.out.println("last指向根结点=>"+last.val);
            }else {
                System.out.println("***************当前根节点***********"+p.val);
                System.out.println("last指向根结点=>"+null);
            }
    
            //转换右子树
            System.out.println("=========递归右子树=========");
            if(root.right!=null) last=convert(root.right,last);
            return last;
        }
    
        public static void main(String[] args){
            //构造二叉排序树
            TreeNode root=new TreeNode(10);
            root.left=new TreeNode(6);
            root.right=new TreeNode(14);
            root.left.left=new TreeNode(4);
            root.left.right=new TreeNode(8);
            root.right.left=new TreeNode(12);
            root.right.right=new TreeNode(16);
    
            TreeNode head = Convert(root);
    
    
        }
    
    
    }
    
    
    --------------------------进入convert方法-------------------------------
    current root=>10
    =========递归左子树=========
    --------------------------进入convert方法-------------------------------
    current root=>6
    =========递归左子树=========
    --------------------------进入convert方法-------------------------------
    current root=>4
    =========递归左子树=========
    ***************当前根节点***********4
    当前列表的最后一个节点(当前左子树的最大节点)=>null
    ***************当前根节点***********4
    根结点的pre指向左子树的last=>null
    ***************当前根节点***********4
    last指向根结点=>4
    =========递归右子树=========
    ***************当前根节点***********6
    当前列表的最后一个节点(当前左子树的最大节点)=>4
    ***************当前根节点***********6
    根结点的pre指向左子树的last=>4
    ***************当前根节点***********6
    last指向根结点=>6
    =========递归右子树=========
    --------------------------进入convert方法-------------------------------
    current root=>8
    =========递归左子树=========
    ***************当前根节点***********8
    当前列表的最后一个节点(当前左子树的最大节点)=>6
    ***************当前根节点***********8
    根结点的pre指向左子树的last=>6
    ***************当前根节点***********8
    last指向根结点=>8
    =========递归右子树=========
    ***************当前根节点***********10
    当前列表的最后一个节点(当前左子树的最大节点)=>8
    ***************当前根节点***********10
    根结点的pre指向左子树的last=>8
    ***************当前根节点***********10
    last指向根结点=>10
    =========递归右子树=========
    --------------------------进入convert方法-------------------------------
    current root=>14
    =========递归左子树=========
    --------------------------进入convert方法-------------------------------
    current root=>12
    =========递归左子树=========
    ***************当前根节点***********12
    当前列表的最后一个节点(当前左子树的最大节点)=>10
    ***************当前根节点***********12
    根结点的pre指向左子树的last=>10
    ***************当前根节点***********12
    last指向根结点=>12
    =========递归右子树=========
    ***************当前根节点***********14
    当前列表的最后一个节点(当前左子树的最大节点)=>12
    ***************当前根节点***********14
    根结点的pre指向左子树的last=>12
    ***************当前根节点***********14
    last指向根结点=>14
    =========递归右子树=========
    --------------------------进入convert方法-------------------------------
    current root=>16
    =========递归左子树=========
    ***************当前根节点***********16
    当前列表的最后一个节点(当前左子树的最大节点)=>14
    ***************当前根节点***********16
    根结点的pre指向左子树的last=>14
    ***************当前根节点***********16
    last指向根结点=>16
    =========递归右子树=========
    
    

    简洁代码

    /**
    public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;
    
        public TreeNode(int val) {
            this.val = val;
    
        }
    
    }
    */
    public class Solution {
       /**
         * 定义:转换后left表示pre,right表示next
         * @param pRootOfTree  根结点
         * @return
         */
        public  TreeNode Convert(TreeNode  pRootOfTree) {
            if(pRootOfTree==null) return pRootOfTree;
            //链表尾节点
            TreeNode lastNode=null;
            //转换
            lastNode=convert(pRootOfTree,lastNode);
            //寻找返回的头结点
            TreeNode head=lastNode;
            while(head.left!=null) {
                head = head.left;
            }
    
            return head;
        }
    
        /**
         * 返回当前已转换好的链表的尾结点
         * @param root  当前子树的根结点
         * @param last  保存当前链表的最后一个指针
         * @return  返回当前链表的最后一个结点
         */
        public  TreeNode convert(TreeNode root,TreeNode last) {
            if(root==null) return null;
            TreeNode p=root;
            //转换左子树
            if(root.left!=null) last=convert(root.left,last);
            //根结点的pre指向左子树的last,左子树的last的next指向根结点
            p.left=last;
            if(last!=null) last.right=p;
            //last指向根结点
            last=p;
            //转换右子树
            if(root.right!=null) last=convert(root.right,last);
            return last;
        }
    
    }
    

    总结

    本题的关键在于如何处理指针的指向,具体包括如何将当前根节点的前一个节点(p.left)指向左子树的最后一个节点(last)=>p.left = last;如何将左子树的最后一个节点的下一个节点(last.right)指向根节点=>last.right = p

    还要注意的是遍历完左子树的时候还需要将当前的根节点加入到链表中,作为新的last=>last = p

    然后再遍历右子树

    整体的思路还是按照中序遍历的结果:处理左子树=>处理根节点和左子树的最后一个的关系=>处理右子树

    参考:

    二叉搜索树转换为双向链表的Java实现 出现的一些问题及解决

  • 相关阅读:
    springboot springdata 整合es
    forkJoinPool
    springboot整合ElasticSearch
    雪花算法生成全局唯一ID
    linux环境下elasticsearch+kibana+ik(实现热词自动更新)
    ECMAScript 6新特性简记
    Tsung:开源多协议分布式负载&压力测试工具
    js 数组迭代方法总结
    js for循环
    箭头函数this的问题
  • 原文地址:https://www.cnblogs.com/flyingcr/p/10428282.html
Copyright © 2020-2023  润新知