数据结构——二叉堆

二叉堆

  • 完全二叉树
  • 高为h的完全二叉树有 2^h~2^(h+1)-1个节点,高为O(log N)
  • insert——插入通过上滤实现,最好为O(1),最坏情况为O(log N),一次插入平均需要2.607次比较,因此平均一次插入上移1.607层
  • deleteMin——删除最小元通过下滤实现,,最坏情况为O(log N),平均时间为O(log N)
  • decreaseKey——降低关键字的值,需要上滤改变堆的结构,提升了优先级
  • increaseKey——增加关键字的值,需要下滤改变堆的结构,降低优先级
  • delete——删除操作可以先decreaseKey,再deleteMin
  • buildHeap——通过N个insert来完成,总的平均时间为O(N)
  • buildHeap——一般是通过先构成数组,再经过N/2次的下滤构造
public class BinaryHeap<T extends Comparable<? super T>> {
    private static final int DEFAULT_CAPACITY = 10;

    private int mCurrentSize;
    private T[] mItems;

    public BinaryHeap() {

    }

    public BinaryHeap(int capacity) {

    }

    public BinaryHeap(T[] items) {
        mCurrentSize = items.length;
        mItems = (T[]) new Comparable[(mCurrentSize + 2) * 11 / 10];
        int i = 1;
        for (T item : items) {
            mItems[i++] = item;
        }
        buildHeap();
    }

    //插入,上滤,将插入节点放在最后,与父比较,小于父,则取代父节点
    public void insert(T t) {
        if (mCurrentSize == mItems.length - 1) {
            enlargeArray(mItems.length * 2 + 1);
        }
        int hole = ++mCurrentSize;
        for (; hole > 1 && t.compareTo(mItems[hole / 2]) < 0; hole = hole / 2) {
            mItems[hole] = mItems[hole / 2];
        }
        mItems[hole] = t;
    }

    public T findMin() {
        return mItems[1];
    }

    //删除最小,下滤
    public T delteMin() {
        if (isEmpty()) {
            throw new NullPointerException();
        }
        T min = findMin();
        mItems[1] = mItems[mCurrentSize--];
        percolateDown(1);
        return min;
    }

    public boolean isEmpty() {
        return mCurrentSize <= 0;
    }

    public void makeEmpty() {
        mCurrentSize = 0;
        mItems = (T[]) new Comparable[DEFAULT_CAPACITY + 1];
    }

    //下滤,子节点关键字小于父,取左右最小的取代父
    private void percolateDown(int hole) {
        int child;
        T tmp = mItems[hole];
        for (; hole * 2 <= mCurrentSize; hole = child) {
            child = hole * 2;
            if (child != mCurrentSize && mItems[child + 1].compareTo(mItems[child]) < 0) {
                child++;
            }
            if (mItems[child].compareTo(tmp) < 0) {
                mItems[hole] = mItems[child];
            } else {
                break;
            }
        }
        mItems[hole] = tmp;
    }

    //通过下滤进行构造
    private void buildHeap() {
        //叶子不需要下滤
        for (int i = mCurrentSize / 2; i > 0; i--) {
            percolateDown(i);
        }
    }

    private void enlargeArray(int newSize) {
        T[] array = (T[]) new Comparable[newSize];
        System.arraycopy(mItems, 0, array, 0, 1 + mCurrentSize);
        mItems = array;
        mCurrentSize = newSize;
    }
}

应用:

  • N个元素找出第k个最小的元素。
  • 将N个元素读入数组,使用buildHeap算法,然后执行k次deleteMin操作,即可得到答案。
  • 复杂度 O(N)+k*O(log N)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值