二叉搜索树

二叉搜索树的定义

  二叉查找树(Binary Search Tree),或者是一颗空树,或者是具有下列性质的二叉树:

1、若它的左子树不空,则其左子树上的所有结点的值均小于它根结点的值;

2、若它的右子树不空,则其右子树上的所有结点的值均大于它根结点的值;

3、它的左、右子树也分别为二叉查找树。

代码实现

树:

public interface Tree<Key extends Comparable & Serializable> {

    /**
     * 中序遍历
     */
    static void inorderTreeWalk(Tree tree) {
        if (tree != null) {
            inorderTreeWalk(tree.getLeft());
            System.out.println(String.valueOf(tree.getKey()));
            inorderTreeWalk(tree.getRight());
        }
    }

    /**
     * 先序遍历
     */
    static void preorderTreeWalk(Tree tree) {
        if (tree != null) {
            System.out.println(String.valueOf(tree.getKey()));
            preorderTreeWalk(tree.getLeft());
            preorderTreeWalk(tree.getRight());
        }
    }

    /**
     * 后序遍历
     */
    static void postorderTreeWalk(Tree tree) {
        if (tree != null) {
            postorderTreeWalk(tree.getLeft());
            postorderTreeWalk(tree.getRight());
            System.out.println(String.valueOf(tree.getKey()));
        }
    }

    Key getKey();

    void setKey(Key key);

    <T extends Tree> T getLeft();

    <T extends Tree> T getRight();

}

二叉搜索树:

  • 插入
  • 前驱后继
  • 搜索
  • 最大最小
  • 删除

当结点的左右子树都不空的时候,一般的删除策略是用其右子树的最小数据(容易找到)代替要删除的结点数据并递归删除该结点(此时为null),因为右子树的最小结点不可能有左孩子,所以第二次删除较为容易。 z的左子树和右子树均不空。找到z的后继y,因为y一定没有左子树,所以可以删除y,并让y的父亲节点成为y的右子树的父亲节点,并用y的值代替z的值.如图:
                    


public class BinarySearchTree<Key extends Comparable & Serializable,Value> implements Tree<Key>{
    private Node<Key, Value> node;
    private BinarySearchTree<Key, Value> left;
    private BinarySearchTree<Key, Value> right;

    class Node<T extends Key, E extends Value> {
        private T key;
        private E value;

        public Node(T key, E value) {
            this.key = key;
            this.value = value;
        }

        public T getKey() {
            return key;
        }

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

        public E getValue() {
            return value;
        }

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


    public void remove(Node<Key, Value> node) {
        remove(this, node);
    }

    @SuppressWarnings("unchecked")
    public BinarySearchTree<Key, Value> remove(BinarySearchTree<Key, Value> binarySearchTree, Node<Key, Value> node) {
        if (binarySearchTree == null || node == null) {
            return null;
        }
        BinarySearchTree current = binarySearchTree;
        BinarySearchTree parent = null;
        while (current != null) {
            if (node.getKey().compareTo(current.getKey()) < 0) {
                parent = current;
                current = binarySearchTree.getLeft();
            } else if (node.getKey().compareTo(current.getKey()) > 0){
                parent = current;
                current = binarySearchTree.getRight();
            } else if (current.getLeft() != null && current.getRight() != null){
                //当结点的左右子树都不空的时候,一般的删除策略是用其右子树的最小数据
                //容易找到)代替要删除的结点数据并递归删除该结点(此时为null),因为
                //右子树的最小结点不可能有左孩子,所以第二次删除较为容易。
                current.setNode(current.getRight().getMin());
                current.setRight(remove(current.getRight(),  current.getNode()));
            } else {
                current = current.getLeft() != null ? current.getLeft() : current.getRight();
            }
        }

        return binarySearchTree;
    }

    /**
     * 插入
     */
    public void insert(Node<Key, Value> node) throws IllegalArgumentException {
        if (node == null) {
            throw new IllegalArgumentException("Cannot insert null entity.");
        }
        insert(this, node);
    }

    public void insert(Key key, Value value) {
        insert(this, new Node<>(key, value));
    }

    public void insert(BinarySearchTree<Key, Value> binarySearchTree, Node<Key, Value> node) {
        if (binarySearchTree == null) {
            throw new IllegalArgumentException("BinarySearchTree must not be null.");
        }

        BinarySearchTree<Key,Value> current = binarySearchTree;
        BinarySearchTree<Key, Value> parent = binarySearchTree;
        boolean isLeftChild = false;
        while (current != null) {
            parent = current;
            if (node.getKey().compareTo(current.getKey()) < 0) {
                current = current.getLeft();
                isLeftChild = true;
            } else {
                current = current.getRight();
            }
        }
        BinarySearchTree<Key, Value> insertTree = new BinarySearchTree<>(node);
        if (isLeftChild) {
            parent.setLeft(insertTree);
        } else {
            parent.setRight(insertTree);
        }
    }

    /**
     * 递归实现,资源消耗往往比较高
     */
    public BinarySearchTree<Key, Value> search(BinarySearchTree<Key, Value> binarySearchTree, Key key) {
        if (binarySearchTree == null || key == binarySearchTree.getKey()) {
            return binarySearchTree;
        }
        if (key.compareTo(binarySearchTree.getKey()) < 0) {
            return search(binarySearchTree.getLeft(), key);
        } else {
            return search(binarySearchTree.getRight(), key);
        }
    }

    public BinarySearchTree<Key, Value> search(Key key) {
        return search(this, key);
    }

    /**
     * 迭代的方式往往更加省力
     */
    public BinarySearchTree<Key, Value> iterativeTreeSearch(BinarySearchTree<Key, Value> binarySearchTree, Key key) {
        while (binarySearchTree != null && key.compareTo(binarySearchTree.getKey()) != 0) {
            if (key.compareTo(binarySearchTree.getKey())  < 0) {
                binarySearchTree = binarySearchTree.getLeft();
            } else {
                binarySearchTree = binarySearchTree.getRight();
            }
        }
        return binarySearchTree;
    }

    public BinarySearchTree<Key, Value> iterativeTreeSearch(Key key) {
        return iterativeTreeSearch(this, key);
    }

    public Node<Key, Value> getMin() {
        BinarySearchTree<Key, Value> binarySearchTree = this;
        while (binarySearchTree.getLeft() != null) {
            binarySearchTree = binarySearchTree.getLeft();
        }
        return binarySearchTree.getNode();
    }

    public Node<Key, Value> getMax() {
        BinarySearchTree<Key, Value> binarySearchTree = this;
        while (binarySearchTree.getRight() != null) {
            binarySearchTree = binarySearchTree.getRight();
        }
        return binarySearchTree.getNode();
    }

    /**
     * 后继:如果所有的关键字互不相同,则一个节点x的后继是大于x.key的最小关键字的节点
     */
    public Node<Key, Value> successor(Key key) {
        // 在二叉搜索树中查找 key 对应的节点
        BinarySearchTree<Key, Value> binarySearchTree = search(key);

        // 如果 key 对应的节点不存在,则 key 没有后继,返回 null
        if (binarySearchTree == null)
            return null;

        // 如果key所在的节点右子树不为空,则其右子树的最小值为key的后继
        if (binarySearchTree.getRight() != null) {
            return binarySearchTree.getRight().getMin();
        }

        // 如果右边的树不存在,那么就找root节点到自己这个节点的路径上有没有后继
        return successorFromAncestor(this, key);
    }

    private Node<Key, Value> successorFromAncestor(BinarySearchTree<Key, Value> binarySearchTree, Key key){
        //该key就是根节点。
        if (key.compareTo(binarySearchTree.getKey()) == 0){
            return null;
        }
        if (key.compareTo(binarySearchTree.getKey()) > 0 ){
            //key 在右边
            return successorFromAncestor(binarySearchTree.getRight(), key);
        }else {
            // key 在左边
            Node minNode = successorFromAncestor(binarySearchTree.getLeft(), key);
            if (minNode != null)
                // minNode和当前节点node取最小值返回
                return minNode.getKey().compareTo(binarySearchTree.getKey()) > 0 ? binarySearchTree.getNode() : minNode;
            else
                // 如果minNode为空, 则当前节点即为结果
                return binarySearchTree.getNode();
        }
    }

    /**
     * 随机构建二叉树
     */
    public BinarySearchTree(List<Node<Key, Value>> nodeList) {
        if (nodeList == null || nodeList.isEmpty()) {
            throw new IllegalArgumentException("Illegal node list.");
        }
        
        BinarySearchTree<Key,Value> root = new BinarySearchTree<Key, Value>(nodeList.get(0));

        for (int i = 1; i < nodeList.size(); i++) {
            root.insert(nodeList.get(i));
        }
    }

    public BinarySearchTree(Node<Key, Value> node) {
        this.node = node;
    }

    public BinarySearchTree(Node<Key, Value> node, BinarySearchTree<Key, Value> left, BinarySearchTree<Key, Value> right) {
        this.node = node;
        this.left = left;
        this.right = right;
    }

    public Node<Key, Value> getNode() {
        return node;
    }

    public void setNode(Node<Key, Value> node) {
        this.node = node;
    }

    @Override
    public Key getKey() {
        return getNode() != null ? getNode().getKey() : null;
    }

    @Override
    public void setKey(Key key) {
        if (getNode() != null) {
            this.getNode().setKey(key);
        }
    }

    public <T extends BinarySearchTree<Key, Value>> void setRight(T right) {
        this.right = right;
    }

    public <T extends BinarySearchTree<Key, Value>> void setLeft(T left) {
        this.left = left;
    }

    @SuppressWarnings("unchecked")
    @Override
    public BinarySearchTree<Key, Value> getLeft() {
        return left;
    }

    @SuppressWarnings("unchecked")
    @Override
    public BinarySearchTree<Key, Value> getRight() {
        return right;
    }

}

时间复杂度

n个节点,h为二叉树的高度

操作时间复杂度
中序/后序/前序遍历o(n)
查找o(h)
最大,最小关键字o(h)
前驱后继o(h)
插入o(h)
删除o(h)
随机构建o(n)

其实在实际情况中,二叉搜索树树往往要求做成二叉平衡搜索树。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值