二叉堆的基本概念与实现

基本概念

二叉堆又名堆,或者优先队列。一般实现在堆顶的元素总是最小的。
二叉堆是一颗用数组实现的完全二叉树。
要实现二叉堆必须满足以下条件:
1堆有序,二叉树中每一个子树的父节点不大于(大根堆)两个子节点。
2树的父节点的两个子节点位置为 2k和2k+1(不使用数组的0号索引),如果使用0号索引,两个子节点的位置为2*k+1和2*k=2。
要实现堆有序,主要依靠上浮(swim)和下沉(snik)两个操作。
在入队时,将数据插入到元素序列尾部,然后将元素上浮到应有的位置。
在出队时,将堆顶最小的元素删除,用元素序列尾部的元素交换到堆顶,然后进行下沉操作,恢复堆有序。

实现

/**
 * 二叉堆,小堆,降序
 * @author yuli
 *
 */
public class BinaryHeap<T extends Comparable<T>>{
    private Comparable<T>[] data;
    private int size;
    private static final int DEFAULT_CAPACITY = 10; 
    public BinaryHeap() {
        clean();
    }
    public void clean(){
        size = 0;
        swap(DEFAULT_CAPACITY);
    }
    /**
     * 添加元素,并将元素上浮
     * @param t
     */
    public void insert(T t){
        if(size+1 >= data.length){
            swap(2*size +1);
        }
        //0号位置要空着,所以+了再放元素
        data[++size] = t;
        swim(size);
    }
    /**
     * 删除元素,并恢复堆有序
     * @return
     */
    public Comparable<T> delete(){
        if(size < 0){
            System.out.println("没元素啦");
            return null;
        }
        //获得堆顶元素
        Comparable<T> t = data[1];
        //将堆顶元素替换成堆底元素
        data[1] = data[size];
        //移除堆底元素,顺便把容器的大小-1
        data[size--] = null;
        //将交换来的元素下沉到合适的位置,恢复堆的有序性
        sink(1);
        return t; 
    }
    /**
     * 上浮元素,如果父节点大于子节点,就上浮元素
     * @param k 元素的索引
     */
    public void swim(int k){
        //如果子元素不是头结点,并且父节点大于子节点就交换
        while(k > 1 && less(data[k],data[k/2])){
            exchange(data, k, k/2);
            k = k/2;
        }
    }

    private void exchange(Comparable<T>[] t,int v,int w){
        Comparable<T> temp = t[v];
        t[v] = t[w];
        t[w] = temp;
    }
    /**
     * 下沉元素,如果元素的子节点大于父节点,就下沉元素
     * @param k 元素的索引
     */
    public void sink(int k){
        while(2*k <= size ){
            //获取子节点
            int j = 2*k;
            //从两个孩子中选出较小那个
            if(j+1 <= size && !less(data[j],data[j+1])){
                j++;
            }
            //如果子节点不小于父节点就不交换
            if(less(data[k],data[j])){
                break;
            }
            exchange(data, k, j);
            k = j;
        }
    }

    /**
     * v是否比w小
     * @param v
     * @param w
     * @return
     */
    public boolean less (Comparable v,Comparable w){
        return v.compareTo(w) < 0 ;
    }
    /**
     * 扩容,交换元素
     * @param newSize
     */
    @SuppressWarnings("unchecked")
    public void swap(int newSize){
        if(newSize < size){
            return;
        }
        Comparable<T>[] newItems = new Comparable[newSize];
        for(int i=0;i<this.size;i++){
            newItems[i+1]=data[i+1];
        }
        this.data = newItems;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值