• 二次排序树


    一.定义

    二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树

    一棵空树,或者是具有下列性质的二叉树
    (1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
    (2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
    (3)左、右子树也分别为二叉排序树;
    (4)没有键值相等的结点。

    二.查找

    步骤

    若根结点的关键字值等于查找的关键字,成功
    否则,若小于根结点的关键字值,递归查左子树。
    若大于根结点的关键字值,递归查右子树。
    若子树为空,查找不成功。
    平均情况分析(在成功查找两种的情况下):
    在一般情况下,设 P(n,i)为它的左子树的结点个数为 i 时的平均查找长度。如图的结点个数为 n = 6 且 i = 3; 则 P(n,i)= P(6, 3) = [ 1+ ( P(3) + 1) * 3 + ( P(2) + 1) * 2 ] / 6= [ 1+ ( 5/3 + 1) * 3 + ( 3/2 + 1) * 2 ] / 6
    注意:这里 P(3)、P(2) 是具有 3 个结点、2 个结点的二叉分类树的平均查找长度。 在一般情况,P(i)为具有 i 个结点二叉分类树的平均查找长度。平均查找长度= 每个结点的深度的总和 / 总结点数
    (上图应为左子树P(3),右子树P(2))
    P(3) = (1+2+2)/ 3 = 5/3
    P(2) = (1+2)/ 2 = 3/2∴ P(n,i)= [ 1+ ( P(i) + 1) * i + ( P(n-i-1) + 1) * (n-i-1) ] / n
    ∴ P(n)=
     P(n,i)/ n <= 2(1+I/n)lnn
    因为 2(1+I/n)lnn≈1.38logn 故P(n)=O(logn)
     

    插入算法

    首先执行查找算法,找出被插结点的父亲结点。
    判断被插结点是其父亲结点的左、右儿子。将被插结点作为叶子结点插入。
    二叉树为空。则首先单独生成根结点。
    注意:新插入的结点总是叶子结点。

    删除结点


                 在二叉排序树删去一个结点,分三种情况讨论:
    1. 若*p结点为叶子结点,即PL(左子树)和PR(右子树)均为空树。由于删去叶子结点不破坏整棵树的结构,则可以直接删除此子结点。
    2. 若*p结点只有左子树PL或右子树PR,此时只要令PL或PR直接成为其双亲结点*f的左子树(当*p是左子树)或右子树(当*p是右子树)即可,作此修改也不破坏二叉排序树的特性。
    3. 若*p结点的左子树和右子树均不空。在删去*p之后,为保持其它元素之间的相对位置不变,可按中序遍历保持有序进行调整,可以有两种做法:
      其一是令*p的左子树为*f的左/右(依*p是*f的左子树还是右子树而定)子树,*s为*p左子树的最右下的结点,而*p的右子树为*s的右子树;
      其二是令*p的直接前驱(或直接后继)替代*p,然后再从二叉排序树中删去它的直接前驱(或直接后继)-即让*f的左子树(如果有的话)成为*p左子树的最左下结点(如果有的话),再让*f成为*p的左右结点的父结点。

    1.创建节点

    public class Node {
        int value;
        Node left;//左节点
        Node right;//右节点
    
        public Node(int value) {
            this.value = value;
        }
    
        /*添加节点的方法满足二叉排序树*/
        public  void add(Node node){
            if (node==null){
                return;
            }
            //判断传入节点和当前子树节点的值
            if (node.value<this.value){
                if (this.left ==null){//左子节点为空直接添加
                  this.left=node;
                }else {
                    this.left.add(node);//递归左子树添加
                }
            }else {//添加的节点大于当前节点的值
                if (this.right==null){
                    this.right=node;
                }else {
                    this.right.add(node);//递归右子树添加
                }
            }
        }
    
        /*中序遍历*/
        public  void infixOrder(){
            if (this.left!=null){
                this.left.infixOrder();
            }
            System.out.println(this);
            if (this.right!=null){
                this.right.infixOrder();
            }
        }
    
    
    
        /*查找要删除的节点*/
        public  Node search(int va1ue){
            if (va1ue == this.value){
                return this;
            }else if (va1ue<this.value){//左节点递归查找
               if (this.left==null){
                   return null;
               }
                return this.left.search(va1ue);
            }else {//右子树递归查找
                if (this.right==null){
                    return null;
                }
                return this.right.search(va1ue);
    
            }
        }
    
    
        /*查找删除节点的父节点*/
        public  Node searchParent(int value){
            if ((this.left!=null &&this.left.value==value)
                    ||(this.right!=null&&this.right.value==value)){
                return this;
            }else {//如果查找的值小于当前节点,并且当前节点不为空
               if (value <this.value && this.left!=null){
                   return this.left.searchParent(value);//左递归
               }else if (value>=this.value && this.right!= null){
                     return  this.right.searchParent(value);
                }else {
                   return null;
               }
            }
        }
        @Override
        public String toString() {
            return "Node{" +
                    "value=" + value +
                    '}';
        }
    }

    2.建立二叉排序树

    public class BinarySearchTree {
        private  Node root;
    
    
    
    
        /*查找要删除的节点*/
        public  Node search(int va1ue){
            if (root==null){
                return null;
            }else {
                return root.search(va1ue);
            }
        }
    
    
        /*查找删除节点的父节点*/
        public  Node searchParent(int value){
            if (root==null){
                return null;
            }else {
                return root.searchParent(value);
            }
        }
    
    
    
        /**
         *
         * @description:TODO
         * @params:1.节点(当做二叉的根节点)
         * 1.删除最小节点
         * @return: 当前节点作为二叉数根节点的最小节点值
         * @author: 苏兴旺
         * @time: 2020/3/14 12:38
         */
        public  int delRightTree(Node node){
            Node targe = node;
            //一直往左边找就是最小值
            while (targe.left!=null){
                targe = targe.left;
            }
            delNode(targe.value); //指向最小节点
            return targe.value;
            
        }
    
    
    
        /*删除节点
         * 1.找待删除的节点taget
         * 2.找到待删除节点的父节点parent
         * 3.确定 taget 是父节点 左节点 右节点
         * 4.根据实际情况进行删除
         * 左节点==null
         * 右节点==null
         *
         * 第二种:删除的节点只有一个子树
         * 1.找待删除的节点taget
         * 2.找到待删除节点的父节点parent
         * 3.确定taget的子节点是左节点还是右子节点
         * 4.taget是parent左子节点还是右子节点
         * 5.如果taget有左子节点
         *    5.1 如果taget是parent左节点 parent.左 = taget.左
         *    5.2如果taget是parent右节点parent.右 = taget.左
         * 6.如果taget有右子节点
         *    6.1 如果taget是parent左节点 parent.左 = taget.右
         *   6.2如果taget是parent右节点parent.右 = taget.右
         *
         * 情况三删除有二个数的节点:
         *.1找待删除的节点taget
         * 2.找到待删除节点的父节点parent
         * 3.从taget 的右节点找到最小的节点
         * 4.用临时变量保存保存最小节点temp
         * 5.删除该节点
         * taget.value=temp*/
    
    
    
    
        public void  delNode(int value){
            if (root == null){
                return;
            }else {
                Node target = search(value);
                if (target == null){//找到删除的节点taget
                    return;
                }
    
                //target 树只有一个root接电脑
                if (root.left==null && root.right==null){
                    root=null;
                    return;
                }
                //找到删除节点的父节点
                Node parent = searchParent(value);
                if (target.left==null&&target.right==null){//为叶子节点
                    if (parent.left!=null &&parent.left.value==value){//判断target节点是父节点的左节点还是右节点
                        parent.left=null;
                    }else if (parent.right!=null&& parent.right.value==value){
                        parent.right=null;
                    }
                }else if (target.left!=null && target.right!=null){//情况三删除有二个数的节点:
                           // 情况三删除有二个数的节点:
                            //1.找待删除的节点taget
                            //2.找到待删除节点的父节点parent
                            // 3.从taget 的右节点找到最小的节点
                            // 4.用临时变量保存保存最小节点temp
                            // 5.删除该节点
                    int minVal = delRightTree(target.right);
                    target.value=minVal;
                }else {//删除的节点只有一个子树
                    if (target.left!=null){//如果要删除的有左子节点
                        if (parent.left.value==value){//target是父节点的左节点
                            parent.left=target.left;
                        }else {//target是父节点的右节点
                            parent.right = target.left;
                        }
                    }else {//如果要删除的有右子节点
                        if (parent.left.value==value){//target是父节点的左节点
                            parent.left=target.right;
                        }else {//target是父节点的右节点
                            parent.right=target.right;
                        }
                    }
                }
    
    
            }
        }
    
    
        /*添加方法*/
        public  void  add(Node node){
            if (root==null){
                root = node;
            }else {
                root.add(node);
            }
        }
    
    
        /*中序遍历*/
        public  void infixOrder(){
            if (root==null){
                System.out.println("二叉排序树为空!!!");
            }else {
                root.infixOrder();
            }
        }
    
    
    
    }

    3.进行测试

    public class BinarySearchTreeDemo {
        public static void main(String[] args) {
            int[] arr = {7,3,10,12,5,1,9,0};
            BinarySearchTree binarySearchTree = new BinarySearchTree();
    
            /*循环添加节点到二叉排序树*/
            for (int i = 0; i < arr.length; i++) {
                binarySearchTree.add(new Node(arr[i]));
            }
    
            /*中序遍历*/
            binarySearchTree.infixOrder();
    
            /*测试删除叶子节点*/
           //binarySearchTree.delNode(2);
            //binarySearchTree.delNode(5);
            binarySearchTree.delNode(10);
            System.out.println("删除后");
            binarySearchTree.infixOrder();
    
        }
    
    }
  • 相关阅读:
    java并发AtomicIntegerArray
    java并发:原子类之AtomicLong
    java并发:初探消费者和生产者模式
    java并发:初探用户线程和守护线程
    java并发:interrupt进程终止
    java并发:join源码分析
    java并发:初探sleep方法
    java并发(二):初探syncronized
    java并发(一):初探线程的创建
    Git 操作
  • 原文地址:https://www.cnblogs.com/sxw123/p/12804410.html
Copyright © 2020-2023  润新知