二叉查找(排序)树 算法简述及java实现

二叉查找树

简述

二叉查找树是一颗二叉树,其每个节点都含有可比较的Key值及一个Value值。其满足其上每个节点的键都大于其左子树中任意节点的键,小于其右子树中任意节点的键。

复杂度

二叉查找树结合了链表的插入灵活性及有序数组的查找高效性,在平均情况下查询复杂度为O( log ( n ) ),插入复杂度与查询复杂度近似。插入本身有序的数据时二叉查找树会退化为单链表,此时无法保证平衡,树的深度为n。

操作描述

  • 查找
    由于二叉查找树的性质易得查找过程如下:
    首先从根节点开始,比较当前节点Key与所查找Key的大小。
    若当前节点Key小于所找的Key,则从当前节点的右子节点继续寻找。
    若当前节点Key大于所找的Key,则从当前节点的左子节点继续寻找。
    若当前节点Key等于所找的Key,则返回对应的值。
    若当前节点不存在,则可知所查找的Key不存在,查找未命中。

  • 插入
    由二叉查找树的性质易得插入过程只需效仿查找过程即可。
    若最后可查找到Key值相同的节点则更新节点的Value。
    若最后无法查找到Key值相同的节点则根据最后到达节点的Key确定操作:
    若最后到达节点的Key值小于欲插入节点的Key,则将新节点作为左子节点。
    若最后到达节点的Key值大于欲插入节点的Key,则将新节点作为右子节点。

  • 删除
    首先进行查找找到待删除节点K,其后按情况而定:
    若待删除节点为叶子节点,则则直接将该节点从树中删除即可。
    若待删除结点只有左子树或只有右子树,则直接使用其左子节点或右子节点直接代替被删除节点即可。
    若待删除节点同时具有左子树及右子树时,需要在被删除节点的右子树中找到最小节点(左子树找最大节点也可)用于代替被删除的节点。

具体实现

删除操作存在重构空间

/**
 * 通用二叉查找树
 * Created by Hzldex on 2018/4/17.
 */
public class BinarySearchTree<Key extends Comparable<Key>, Value> {

    private BSTNode root;

    public static void main(String[] args) {
        BinarySearchTree<String, Integer> binarySearchTree = new BinarySearchTree<>();
        binarySearchTree.insert("q", 60);
        binarySearchTree.insert("a", 40);
        binarySearchTree.insert("z", 20);
        binarySearchTree.insert("d", 10);
        binarySearchTree.insert("c", 30);
        System.out.println(binarySearchTree.get("q"));
        binarySearchTree.delete("q");
        System.out.println(binarySearchTree.get("q"));
        System.out.println(binarySearchTree.get("a"));

    }

    public Value get(Key key) {
        BSTNode curNode = root;
        while (curNode != null) {
            int result = curNode.compareTo(key);
            if (result > 0) { // key小于当前节点的key
                curNode = curNode.left; // 进入左子树
            } else if (result < 0) { //key大于当前结点的key
                curNode = curNode.right; // 进入右子树
            } else {
                return curNode.value; //返回值
            }

        }
        return null; //未找到
    }

    public void insert(Key key, Value value) {
        if (root == null) {  //搜索树为空只需建立根节点放入键值
            root = new BSTNode(key, value);
        } else {
            int cmpResult;
            BSTNode curParent = root;
            BSTNode curNode = root;

            while (curNode != null) {
                cmpResult = curNode.compareTo(key);
                curParent = curNode;
                if(cmpResult > 0){ //若key小于节点
                    curNode = curNode.left; //进入左子树
                }else if(cmpResult < 0){ //若key搭滴于节点
                    curNode = curNode.right; //进入右子树
                }else{
                    curNode.value = value; //更新值
                    return; //插入完成 退出
                }

            }

            BSTNode newNode = new BSTNode(key, value); //前面未更新值则必需要新建节点
            if (curParent.compareTo(key) > 0) { //若key小于其父节点的key
                curParent.left = newNode; //新节点插入左子树
            } else {
                curParent.right = newNode; //新节点插入右子树
            }
        }
    }

    public void delete(Key key) {
        if (root.compareTo(key) == 0) { //若根节点为欲删除节点
            if(root.left == null){ //若根节点无左子树
                root = root.right; //将根节点替换为其右子树
            }else if(root.right == null){
                root = root.left;
            }else{
                BSTNode curParent = root;  //搜索右子树中最小值
                BSTNode curNode = root.right;
                while(curNode.left!= null){
                    curParent = curNode;
                    curNode = curNode.left;
                }
                root.key = curNode.key;
                root.value = curNode.value;
                if(curParent == root){ //若根节点右子节点即为其右子树最小值
                    curParent.right = curNode.right;
                }else{
                    curParent.left = curNode.right;
                }

            }
        } else {
            int cmpResult;
            BSTNode curParent = root;
            BSTNode curNode = root;
            boolean isFind = false;
            while (curNode != null) { //搜索找到欲删除节点
                cmpResult = curNode.compareTo(key);
                if(cmpResult > 0){
                    curParent = curNode;
                    curNode = curNode.left;
                }else if(cmpResult < 0){
                    curParent = curNode;
                    curNode = curNode.right;
                }else {
                    isFind = true;
                }
                if (isFind) break;
            }
            if (isFind) {
                if (curNode.left == null) { // 判断是否只存在左子树或只存在右子树
                    if (curParent.compareTo(key) > 0) {
                        curParent.left = curNode.right;
                    } else {
                        curParent.right = curNode.right;
                    }
                } else if (curNode.right == null) {
                    if (curParent.compareTo(key) > 0) {
                        curParent.left = curNode.left;
                    } else {
                        curParent.right = curNode.left;
                    }
                } else {  // 两边子树都存在的情况
                    BSTNode delNode = curNode;
                    curParent = curNode;
                    curNode = curNode.right;
                    while (curNode.left != null) {//找右子树最小值
                        curParent = curNode;
                        curNode = curNode.left;
                    }
                    delNode.key = curNode.key;//与被删除节点交换键值
                    delNode.value = curNode.value;
                    if(curParent ==delNode){//删除与被删除节点交换的节点
                        curParent.right = curNode.right;
                    }else{
                        curParent.left = curNode.right;
                    }

                }
            }
        }


    }

    class BSTNode implements Comparable<BSTNode> {
        BSTNode left = null, right = null;
        Key key;
        Value value;

        BSTNode(Key key, Value value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public int compareTo(BSTNode o) {
            return this.getKey().compareTo(o.getKey());
        }

        int compareTo(Key o) {
            return this.getKey().compareTo(o);
        }

        public BSTNode getLeft() {
            return left;
        }

        public void setLeft(BSTNode left) {
            this.left = left;
        }

        public BSTNode getRight() {
            return right;
        }

        public void setRight(BSTNode right) {
            this.right = right;
        }

        public Key getKey() {
            return key;
        }

        public void setKey(Key key) {
            this.key = key;
        }

        public Value getValue() {
            return value;
        }

        public void setValue(Value value) {
            this.value = value;
        }
    }

}

    原文作者:Hzldex
    原文地址: https://www.jianshu.com/p/1208e0feef75
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞