美文网首页数据结构和算法
笔记5- 二叉排序树简介。 树和二叉树和森林之间的转换

笔记5- 二叉排序树简介。 树和二叉树和森林之间的转换

作者: 李星星星星星 | 来源:发表于2018-12-18 19:56 被阅读0次

    二叉排序树(查找树,搜索树)

    二叉排序树属于二叉树的一种:
    当一个二叉树或者是一颗空树,或者是一颗具有如下性质的树:
    1)若左子树不为空,那么左子树上面的所有节点的关键字值都比根节点的关键字值小
    2)若右子树不为空,那么右子树上面的所有节点的关键字值都比根节点的关键字值大
    3)左右子树都为二叉树
    4)没有重复值(这一点在实际中可以忽略)
    这棵二叉树可以称为二叉排序树,用二叉排序树可以很快的用来查询和搜索。


    image.png

    下面简单的介绍一个二叉排序树的增删改查方法:
    1.生成一个空树:

    public class SearchBinaryTree {
        
        //根节点
        public TreeNode rootNode;
        
        public class TreeNode{
            int data;
            TreeNode leftChild;
            TreeNode rightChild;
            TreeNode parent;
            
            public TreeNode(int data){
                this.data = data;
                this.leftChild = null;
                this.rightChild = null;
                this.parent = null;
            }
        }
    }
    
    
    image.png

    2.添加一个节点:

        // 添加一个节点
        public TreeNode put(int data){
            if(rootNode==null){
                TreeNode node=new TreeNode(data);
                rootNode=node;
                return node;
            }
            TreeNode parent=null;
            TreeNode node=rootNode;
            //找到要放入的位置
            while(node!=null){
                parent=node;
                if(data<node.data){
                    node=node.leftChild;
                }else if(data>node.data){
                    node=node.rightChild;
                }else{//是重复值 就不理会了
                    return node;
                }
            }
            //生成一个节点放入
            TreeNode newNode=new TreeNode(data);
            if(data<parent.data) {
                parent.leftChild = newNode;
            }else{
                parent.rightChild=newNode;
            }
            newNode.parent=parent;
    
            return newNode;
        }
    

    3.查找一个节点:

        /**
         * 查找一个节点
         */
        public TreeNode searchNode(int data){
            if(rootNode==null){
                return null;
            }
            TreeNode node=rootNode;
            while(node!=null){
                if(node.data==data){
                    return node;
                }else if(data>node.data){
                    node=node.rightChild;
                }else if(data<node.data){
                    node=node.leftChild;
                }
            }
            return null;
        }
    

    4.删除一个节点:

    1.节点是叶子 image.png
    2.只有左孩子 image.png
    3.只有右孩子 image.png
    4.左右孩子都有 image.png
        /**
         * 删除节点
         * 要删除的节点在树上是一定存在的才删除
         * 
         * TODO 把一些引用置空
         * 此处删除方法只是为了说清思路,还会有更优化的删除方法,大家可以参考Java中的 TreeMap类
         */
        public void delNode(TreeNode node){
            if(node==null){
                throw new NoSuchElementException();
            }else{
                //先得到父亲,方便后面的操作
                TreeNode parent=node.parent;
                //1.叶子
                if(node.leftChild==null && node.rightChild==null){
                    //特别的情况:1.树上只有一个节点或是空树
                    if(parent==null){
                        rootNode=null;
                    }else if(parent.rightChild==node){
                        parent.rightChild=null;
                    }else if(parent.leftChild==node){
                        parent.leftChild=null;
                    }
                    node.parent=null;
                }else if(node.leftChild!=null && node.rightChild==null){
                    //2.只有左孩子
                    if(parent==null){//如果要删除的是根
                        node.parent=null;
                        node.leftChild.parent=null;
                        rootNode=node.leftChild;
                    }else{
                        if(parent.leftChild==node){//要删除的节点是父亲的左边
                            node.leftChild.parent=parent;
                            parent.leftChild=node.leftChild;
    
                        }else{//要删除的节点是父亲的右边
                            node.leftChild.parent=parent;
                            parent.rightChild=node.leftChild;
                        }
                        node.parent=null;
                    }
    
                }else if(node.leftChild==null && node.rightChild!=null){
                    //3.只有右孩子
                    if(parent==null){//如果要删除的是根
                        node.parent=null;
                        node.rightChild.parent=null;
                        rootNode=node.rightChild;
                    }else{
                        if(parent.leftChild==node){//要删除的节点是父亲的左边
                            node.rightChild.parent=parent;
                            parent.leftChild=node.rightChild;
                        }else{//要删除的节点是父亲的右边
                            node.rightChild.parent=parent;
                            parent.rightChild=node.rightChild;
                        }
                        node.parent=null;
                    }
                }else{//4。有左右两个孩子
                    if(node.rightChild.leftChild==null){//1.如果被删除节点的右子树的左子树为空,就直接补上右子树
                        node.rightChild.leftChild=node.leftChild;
                        if(parent==null){
                            rootNode=node.rightChild;
                        }else{
                            if(parent.leftChild==node){
                                parent.leftChild=node.rightChild;
                                //
                            }else{
                                parent.rightChild=node.rightChild;
                                //
                            }
                        }
                        node.parent=null;
                    }else{//2.否则就要补上右子树的左子树上最小的一个
                        TreeNode leftNode=getMinLeftTreeNode(node.rightChild);
                        //1
                        leftNode.leftChild=node.leftChild;
                        //2
                        TreeNode leftNodeP=leftNode.parent;
                        leftNodeP.leftChild=leftNode.rightChild;
                        //3
                        leftNode.rightChild=node.rightChild;
                        //4
                        if(parent==null){
                            rootNode=leftNode;
                        }else{
                            if(parent.leftChild==node){
                                parent.leftChild=leftNode;
                                //
                            }else{
                                parent.rightChild=leftNode;
                                //
                            }
                        }
                    }
                }
            }
        }
    

    这样就基本完成了一个可以增删查的二叉树:

    import java.util.NoSuchElementException;
    
    /**
     * 二叉排序树
     * @author LiXin
     *
     */
    public class SearchBinaryTree {
        
        //根节点
        public TreeNode rootNode;
        
        // 添加一个节点
        public TreeNode put(int data){
            if(rootNode==null){
                TreeNode node=new TreeNode(data);
                rootNode=node;
                return node;
            }
            TreeNode parent=null;
            TreeNode node=rootNode;
            //找到要放入的位置
            while(node!=null){
                parent=node;
                if(data<node.data){
                    node=node.leftChild;
                }else if(data>node.data){
                    node=node.rightChild;
                }else{//是重复值 就不理会了
                    return node;
                }
            }
            //生成一个节点放入
            TreeNode newNode=new TreeNode(data);
            if(data<parent.data) {
                parent.leftChild = newNode;
            }else{
                parent.rightChild=newNode;
            }
            newNode.parent=parent;
    
            return newNode;
        }
        
        /**
         * 中序遍历
         * @param rootNode
         */
        public void midOrderTraverse(TreeNode rootNode){
            if(rootNode == null){
                return;
            }
            midOrderTraverse(rootNode.leftChild);
            System.out.print(rootNode.data);
            midOrderTraverse(rootNode.rightChild);
        }
        
        /**
         * 查找一个节点
         */
        public TreeNode searchNode(int data){
            if(rootNode==null){
                return null;
            }
            TreeNode node=rootNode;
            while(node!=null){
                if(node.data==data){
                    return node;
                }else if(data>node.data){
                    node=node.rightChild;
                }else if(data<node.data){
                    node=node.leftChild;
                }
            }
            return null;
        }
    
    
        /**
         * 删除节点
         * 要删除的节点在树上是一定存在的才删除
         * 
         * TODO 把一些应用置空
         */
        public void delNode(TreeNode node){
            if(node==null){
                throw new NoSuchElementException();
            }else{
                //先得到父亲,方便后面的操作
                TreeNode parent=node.parent;
                //1.叶子
                if(node.leftChild==null && node.rightChild==null){
                    //特别的情况:1.树上只有一个节点或是空树
                    if(parent==null){
                        rootNode=null;
                    }else if(parent.rightChild==node){
                        parent.rightChild=null;
                    }else if(parent.leftChild==node){
                        parent.leftChild=null;
                    }
                    node.parent=null;
                }else if(node.leftChild!=null && node.rightChild==null){
                    //2.只有左孩子
                    if(parent==null){//如果要删除的是根
                        node.parent=null;
                        node.leftChild.parent=null;
                        rootNode=node.leftChild;
                    }else{
                        if(parent.leftChild==node){//要删除的节点是父亲的左边
                            node.leftChild.parent=parent;
                            parent.leftChild=node.leftChild;
    
                        }else{//要删除的节点是父亲的右边
                            node.leftChild.parent=parent;
                            parent.rightChild=node.leftChild;
                        }
                        node.parent=null;
                    }
    
                }else if(node.leftChild==null && node.rightChild!=null){
                    //3.只有右孩子
                    if(parent==null){//如果要删除的是根
                        node.parent=null;
                        node.rightChild.parent=null;
                        rootNode=node.rightChild;
                    }else{
                        if(parent.leftChild==node){//要删除的节点是父亲的左边
                            node.rightChild.parent=parent;
                            parent.leftChild=node.rightChild;
                        }else{//要删除的节点是父亲的右边
                            node.rightChild.parent=parent;
                            parent.rightChild=node.rightChild;
                        }
                        node.parent=null;
                    }
                }else{//4。有左右两个孩子
                    if(node.rightChild.leftChild==null){//1.如果被删除节点的右子树的左子树为空,就直接补上右子树
                        node.rightChild.leftChild=node.leftChild;
                        if(parent==null){
                            rootNode=node.rightChild;
                        }else{
                            if(parent.leftChild==node){
                                parent.leftChild=node.rightChild;
                                //此处要删除引用...
                            }else{
                                parent.rightChild=node.rightChild;
                                //此处要删除引用...
                            }
                        }
                        node.parent=null;
                    }else{//2.否则就要补上右子树的左子树上最小的一个
                        TreeNode leftNode=getMinLeftTreeNode(node.rightChild);
                        //1
                        leftNode.leftChild=node.leftChild;
                        //2
                        TreeNode leftNodeP=leftNode.parent;
                        leftNodeP.leftChild=leftNode.rightChild;
                        //3
                        leftNode.rightChild=node.rightChild;
                        //4
                        if(parent==null){
                            rootNode=leftNode;
                        }else{
                            if(parent.leftChild==node){
                                parent.leftChild=leftNode;
                                //此处要删除引用...
                            }else{
                                parent.rightChild=leftNode;
                               //此处要删除引用...
                            }
                        }
                    }
                }
            }
        }
        /**
         * 获取左子树上最小的一个
         * @param node
         * @return
         */
        private TreeNode getMinLeftTreeNode(TreeNode node) {
            TreeNode currootNode=null;
            if(node==null){
                return null;
            }else{
                currootNode=node;
                while(currootNode.leftChild!=null){
                    currootNode=currootNode.leftChild;
                }
            }
            return currootNode;
        }
        
        
        public class TreeNode{
            int data;
            TreeNode leftChild;
            TreeNode rightChild;
            TreeNode parent;
            
            public TreeNode(int data){
                this.data = data;
                this.leftChild = null;
                this.rightChild = null;
                this.parent = null;
            }
        }
    }
    
    

    树 森林 二叉树的转化

    1.树转化成二叉树:


    image.png image.png

    2.森林转化成二叉树:

    image.png
    image.png

    3.二叉树转成树:


    image.png image.png

    4.二叉树转化成森林:

    image.png image.png

    相关文章

      网友评论

        本文标题:笔记5- 二叉排序树简介。 树和二叉树和森林之间的转换

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