二叉查找树--BinarySearchTree

一、定义Tree接口
public interface Tree<E> extends Iterable<E> {
    boolean search(E e);
    boolean insert(E e);
    boolean delete(E e);
    void inorder(); //中序遍历
    void preorder();//前序遍历
    void postorder();//后序遍历
    int getSize();
    boolean isEmpty();
    void clear();
}

二、实现抽象便利类AbstractTree

public abstract class AbstractTree<E> implements Tree<E> {
    @Override
    public void inorder() {

    }

    @Override
    public void preorder() {

    }

    @Override
    public void postorder() {

    }

    @Override
    public boolean isEmpty() {
        return getSize()==0;
    }
}

三、实现BST

public class BinarySearchTree<E extends Comparable<E>> extends AbstractTree<E>{
    protected TreeNode<E> root;
    protected int size = 0;

    public BinarySearchTree(){}
    public BinarySearchTree(E[] objects){
        for(E object:objects){
            insert(object);
        }
    }
    public TreeNode<E> getRoot() {
        return root;
    }

    public static class TreeNode<E extends Comparable<E>>{
        protected E element;
        protected TreeNode<E> leftNode;
        protected TreeNode<E> rightNode;

        public TreeNode(E element) {
            this.element = element;
        }
    }

    protected TreeNode<E> createNewNode(E e){
        return new TreeNode<>(e);
    }

    @Override
    public boolean search(E e) {
        TreeNode<E> current = root;
        while (current != null){
            if(e.compareTo(current.element) > 0){
                current = current.rightNode;
            }
            else if(e.compareTo(current.element) < 0){
                current = current.leftNode;
            }
            else
                return true;
        }
        return false;
    }

    @Override
    public boolean insert(E e) {
        if (root == null)
            root = createNewNode(e);
        else {
            TreeNode<E> parent = root;
            TreeNode<E> current = root;
            while (current != null){
                if (e.compareTo(current.element) > 0){
                    parent = current;
                    current = current.rightNode;
                }
                else if(e.compareTo(current.element) < 0){
                    parent = current;
                    current = current.leftNode;
                }
                else
                    return false; //不能插入相同元素
            }

            if (e.compareTo(parent.element) > 0){
                parent.rightNode = createNewNode(e);
            }
            else{
                parent.leftNode = createNewNode(e);
            }
        }
        size++;
        return true;
    }

    @Override
    public boolean delete(E e) {
        TreeNode<E> parent = null;
        TreeNode<E> current = root;

        while(current!=null){
            if (e.compareTo(current.element)>0){
                parent = current;
                current = current.rightNode;
            }
            else if (e.compareTo(current.element)<0){
                parent = current;
                current = current.leftNode;
            }
            else break;
        }

        if (current == null) return false; //元素不在二叉树中

        if(current.leftNode == null){      //如果要删除的节点没有左子树
            if (parent == root)
                root = current.rightNode;
            else {
                if (e.compareTo(parent.element) > 0)
                    parent.rightNode = current.rightNode;
                else
                    parent.leftNode = current.rightNode;
            }
        }
        else{                                       //如果要删除的节点有左子树,
            TreeNode<E> parentOfRightMost = current;
            TreeNode<E> rightMost = current.leftNode;

            while (rightMost.rightNode != null){    //找出出左子树中最右的子节点,即左子树中最大的子节点rightMost
                parentOfRightMost = rightMost;
                rightMost = rightMost.rightNode;
            }
            current.element = rightMost.element;    //把左子树中最大的节点替换掉要删掉的节点

            if (parentOfRightMost == current)
                parentOfRightMost.leftNode = rightMost.leftNode;
            else
                parentOfRightMost.rightNode = rightMost.leftNode;
        }
        size--;
        return true;
    }

    @Override
    public void inorder() {
        inorder(root);
    }
    protected void inorder(TreeNode<E> root){
        if (root == null) return;
        inorder(root.leftNode);
        System.out.print(root.element+" ");
        inorder(root.rightNode);
    }
    @Override
    public void preorder() {
        preorder(root);
    }
    protected void preorder(TreeNode<E> root){
        if (root == null) return;
        System.out.print(root.element+" ");
        preorder(root.leftNode);
        preorder(root.rightNode);
    }

    @Override
    public void postorder() {
        postorder(root);
    }
    protected void postorder(TreeNode<E> root){
        if (root == null) return;
        postorder(root.leftNode);
        postorder(root.rightNode);
        System.out.print(root.element+" ");
    }
    @Override
    public int getSize() {
        return size;
    }

    @Override
    public void clear() {
        root = null;
        size = 0;
    }


    private class InorderIterator implements Iterator<E>{
        private ArrayList<E> list = new ArrayList<>();
        private int current = 0;
        public InorderIterator(){
            inorder();
        }
        private void inorder(){
            inorder(root);
        }
        private void inorder(TreeNode<E> root){
            if (root == null) return;
            inorder(root.leftNode);
            list.add(root.element);
            inorder(root.rightNode);
        }

        @Override
        public void remove() {
            delete(list.get(current));
            list.clear();
            inorder();
        }

        @Override
        public boolean hasNext() {
            return current<list.size();
        }

        @Override
        public E next() {
            return list.get(current++);
        }
    }

    @Override
    public Iterator iterator() {
        return new InorderIterator();
    }

    public ArrayList<TreeNode<E>> getPath(E e){
        ArrayList<TreeNode<E>> list = new ArrayList<>();
        TreeNode<E> current = root;
        while (current != null){
            list.add(current);
            if(e.compareTo(current.element)>0)
                current = current.rightNode;
            else if (e.compareTo(current.element)<0)
                current = current.leftNode;
            else
                break;
        }
        return list;
    }

}

四、总结

        1.前序、中序、后序遍历的时间复杂度都是O(n),因为每个节点都要遍历一次。查找、删除和插入的时间复杂度是树的高度。在最差的情况下,树的高度为O(n)但如果是平衡二叉树,高度则是O(logn)

        2.如果是平衡二叉树,树的大部分操作需要从上至下一层层的查找树的节点,对于一棵满树,大约有一半的节点处于最底层(最底层节点数 = 其它层节点数的和 + 1),故节点操作大约有一半需要找到最底层节点,大约有四分之一的节点处于倒数第二层,故节点操作大约有四分之一需要找到倒数第二层节点,依此类推

查找过程中,需要访问每一层的节点,故只要知道了查找的层数,就能知道操作所需的时间,如果节点总数为N,层数为L,L=log2(N+1)

如果为查找操作或删除操作,被操作的节点可能是是树的任意节点,故查找操作或删除操作的时间复杂度为:1/21*log2(N+1) + 1/22*log2(N/2+1) + ... + 1/2N*1

如果为插入操作,由于每次都在树的最低层插入新的节点,故插入操作的时间复杂度为:log2(N+1)

总的来说可以认为二叉搜索树操作的时间复杂度为为O(logN)

如果树不是一棵满树,则判断起来比较复杂,但是如果层数相同,对满树的操作肯定比对不满树的操作更耗时

对于一个含有10000个数据项的有序链表,查找操作平均需要比较5000次,对于一个含有10000个节点的二叉搜索树,查找操作大约需要13次

对于一个含有10000个数据项的有序数组,插入操作平均需要移动5000次(对于比较次数,使用不同的算法比较次数并不相同),对于一个含有10000个节点的二叉搜索树,插入操作只需大约13次比较就可找到待插入节点的插入位置,并且由于该位置总是处于二叉搜索树的最底层,并不需要移动其它的节点

可以看出,二叉搜索树集合了有序链表插入删除效率高和有序数组查询效率高的优点


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值