二次排序树

一.定义

二叉排序树(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();

    }

}

 

 

posted @ 2020-04-29 20:21  苏先生139  阅读(228)  评论(0编辑  收藏  举报