【数据结构】优先队列(堆)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/LoveHYZH/article/details/79120744

1.什么是优先队列

  • 支持插入和删除最小值操作,或者插入和删除最大值操作,等价于队列的入队和出队操作
  • 根据优先级高低而不是先到先服务的方式来进行调度
  • 如果最小键值元素拥有最高优先级,那么这种优先队列叫做升序优先队列
  • 如果最大键值元素拥有最高优先级,那么这种优先队列叫做降序优先队列
  • 一般用堆实现

2.优先队列ADT

  • 优先队列的主要操作
    优先队列是元素的容器,每个元素有一个相关键值
    insert(key, data):插入键值为key的数据到优先队列,元素以其key进行排序
    deleteMin()/deleteMax():删除并返回最值元素
    getMinimum()/getMaximum():返回最值元素,但不删除
  • 优先队列的辅助操作
    查找第 k 大/小的元素
    返回优先队列的大小(元素个数)
    堆排序(Heap Sort)

3.堆(二叉堆已经足够满足需求)

  1. 什么是堆
    堆是一棵具有特定性质的二叉树
    堆的基本要求是堆中所有节点的值必须大于等于(或者小于等于)其孩子节点的值
    堆应该是一棵完全二叉树
  2. 堆的表示
    由于堆在形式上是一棵完全二叉树,所以用数组不会浪费存储空间

4.堆的实现

public class Heap {
    public static enum HeapType{
        MaxHeap,
        MinType;
    }
    private int[] ary;
    private int size; //堆中元素个数
    private int capacity; //堆的大小
    private HeapType heapType; //堆的类型

    /**
     * 创建堆
     * @param heapType  堆的类型
     * @param capacity  堆的大小
     */
    public Heap(HeapType heapType){
        this.heapType = heapType;
        this.capacity = 10;
        this.size = 0;
        this.ary = new int[capacity];
    }

    /**
     * @param i 元素在数组中的下标
     * @return  父元素在数组中的下标, 返回-1表示不存在双亲
     */
    private int parentIndex(int i){
        if(i <= 0 || i >= this.size){
            return -1; //不存在双亲节点
        }
        return (i - 1) / 2;
    }

    /**
     * @param i 元素在数组中的下标
     * @return  左孩子在数组中的下标, 返回-1表示不存在左孩子
     */
    private int lchildIndex(int i){
        int left = 2 * i + 1;
        if(left > size){
            return -1;
        }
        return left;
    }

    /**
     * @param i 元素在数组中的下标
     * @return  右孩子在数组中的下标, 返回-1表示不存在右孩子
     */
    private int rchildIndex(int i){
        int right = 2 * i + 2;
        if(right > size){
            return -1;
        }
        return right;
    }

    /**
     * @return 获得堆顶元素
     */
    public int top(){
        if(size <= 0){
            throw new NoSuchElementException("堆为空");
        }
        return ary[0];
    }

    /**
     * 最大堆堆化(下渗)
     * @param i 节点下标
     */
    private void maxHeapPercolateDown(int i){
        int l, r, max;
        int temp;
        l = lchildIndex(i);
        r = rchildIndex(i);
        if(l != -1 && ary[l] > ary[i]){
            max = l;
        }else{
            max = i;
        }
        if(r != -1 && ary[r] > ary[max]){
            max = r;
        }
        if(i != max){
            temp = ary[i];
            ary[i] = ary[max];
            ary[max] = temp;
            maxHeapPercolateDown(max);
        }
    }

    /**
     * 最小堆堆化(下渗)
     * @param i 节点下标
     */
    private void minHeapPercolateDown(int i){
        int l, r, min;
        int temp;
        l = lchildIndex(i);
        r = rchildIndex(i);
        if(l != -1 && ary[l] < ary[i]){
            min = l;
        }else{
            min = i;
        }
        if(r != -1 && ary[r] < ary[min]){
            min = r;
        }
        if(i != min){
            temp = ary[i];
            ary[i] = ary[min];
            ary[min] = temp;
            minHeapPercolateDown(min);
        }
    }


    /**
     * @return  删除并返回堆顶元素
     */
    public int remove(){
        if(size == 0){
            throw new RuntimeException("堆为空,不允许删除元素");
        }
        int temp = ary[0];
        ary[0] = ary[size--];
        switch(heapType){
            case MaxHeap:
                maxHeapPercolateDown(0);
                break;
            default:
                minHeapPercolateDown(0);
        }
        return temp;
    }

    /**
     * @param i 最大堆指定元素上浮
     */
    private void maxHeapPercolateUp(int i){
        int temp;
        int p =parentIndex(i);
        if(p != -1 && ary[i] > ary[p]){
            temp = ary[i];
            ary[i] = ary[p];
            ary[p] = temp;
            maxHeapPercolateUp(p);
        }
    }

    /**
     * @param i 最小堆指定元素上浮
     */
    private void minHeapPercolateUp(int i){
        int temp;
        int p =parentIndex(i);
        if(p != -1 && ary[i] < ary[p]){
            temp = ary[i];
            ary[i] = ary[p];
            ary[p] = temp;
            minHeapPercolateUp(p);
        }
    }

    //扩容
    private void resizeHeap(int newCapacity){
        int[] old_ary = ary;
        capacity *= 2;
        if(capacity < newCapacity){
            capacity = newCapacity;
        }
        this.ary = new int[capacity];
        System.arraycopy(old_ary, 0, ary, 0, size);

    }

    /**
     * 插入元素
     * @param data 
     */
    public void add(int data){
        if(size == capacity){
            resizeHeap(size + 1);
        }
        ++size;
        ary[size - 1] = data;
        switch(heapType){
            case MaxHeap:
                maxHeapPercolateUp(size - 1);
                break;
            default:
                minHeapPercolateUp(size - 1);
        }
    }

    /**
     * 插入数组
     * @param data
     */
    public void add(int[] data){
        int n = data.length;
        if(size == capacity){
            resizeHeap(size + n);
        }
        for(int i = 0; i < n; i++){
            ++size;
            ary[size - 1] = data[i];
        }
        switch(heapType){
            case MaxHeap:
                for(int i = parentIndex(size - 1); i >= 0; i--){
                    maxHeapPercolateDown(i);
                }
                break;
            default:
                for(int i = parentIndex(size - 1); i >= 0; i--){
                    minHeapPercolateDown(i);
                }
        }
    }

    /**
     * 清空堆
     */
    public void clear(){
        size = 0;
        ary = null;
    }
}

猜你喜欢

转载自blog.csdn.net/LoveHYZH/article/details/79120744