用有序二叉堆实现优先队列

优先队列

优先队列要提供并实现两个操作

  • 删除并返回最大元素
  • 插入元素

优先队列的实现

优先队列的实现采用有序二叉堆形式,采用链表或堆栈也可实现,但时间复杂度较高。这里不再赘述。

有序二叉堆的特点

  • 所有根结点必定不小于其两个叶子节点
  • 如果某个节点对应的数组下标为k,则其根节点为k/2,其叶子节点为2k和2k+1
  • 有序二叉堆通过数组实现,采用数组a[N+1]描述有序二叉堆中第一个到最后一个节点(数组元素a[0]不使用,从a[1]开始)。
  • 如图所示:
    这里写图片描述

有序二叉堆的主要操作

  • 上浮
    插入新元素到堆中时,先将该元素置于数组末尾,再上浮至正确节点
  • 下沉
    移除根节点元素时(假设根节点为最大元素),将数组末尾元素置于根节点,再下沉至正确位置
public class MaxPQ<T extends Comparable<T>>{
    private T[] a;
    private int index= 0;//指向末尾元素
    private int N;//记录数组的大小

    public MaxPQ(int size){
        N = size;
        a = (T[])new Comparable[](size + 1);
    }
    //插入新元素到堆中
    public void insert(T item){
        //插入前检测数组是否需要扩容
        if (index >= N * 0.75) {
            resize(a);
            N = a.length;
        }
        //指针指向新的末尾元素
        a[++index] = item;
        //上浮至正确节点位置
        swim(index);
    }

    private void swim(int k){
        while(k > 1 && a[k] > a[k/2]){
            swap(k, k/2);
            k = k / 2;//每上浮一次,k要变为其父节点位置
        }
    }
    //从堆中移除最大元素
    private T removeMax(){
        T max = a[1];
        a[1] = a[index];//将末尾元素当作新的根节点
        a[index] = null;//防止对象游离
        index--;
        sink(1);//将根节点元素下沉至正确位置
        return max;
    }

    private T sink(int k){
        while(k* 2 < N){
            int j = 2 * k;//j记录叶子节点位置
            if (a[j] < a[j+1]) {j++};//j移动到两个叶子节点中较大的那个
            if (a[k] > a[j]) {break};//如果父节点大于叶子节点,说明位置已找到,跳出循环
            swap(k, j);//否则将父节点和叶子节点交换
            k = j;
        }
    }
    //数组扩容函数 
    private void resize(T[] a){
        T[] temp = (T[])new Object[N * 2];
        for (int i = 0; i < a.length; i++) {
            temp[i] = a[i];
        }
        a = temp;
    }
}
展开阅读全文

没有更多推荐了,返回首页