优先级队列(堆)

Posted 可乐好哇!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了优先级队列(堆)相关的知识,希望对你有一定的参考价值。

概念

   数据结构应该提供两个最基本的操作,一个是返回最高级优先级对象,一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue)

  1. 堆逻辑上是一个完全二叉树
  2. 堆物理上是保存在数组中
  3. 满足任意节点的值都大于他子树中结点的值,叫做大堆,或大根堆
  4. 反之,叫做小堆,或小根堆
  5. 堆的基本作用是快速找集合中的最值

三级目录

内部原理

    优先级队列的实现方式有很多,但最常见的是使用堆来构建

操作步骤

  向下调整

  1. 左右子树必须是一个堆,才能调整
  2. 如果已经是叶子结点,则整个调整过程结束
    1.判断当前位置有没有孩子
    2.堆是完全二叉树,没有左孩子就一定没有右孩子,要判断是否有左孩子
    3.堆的存储结构是数组,判断是否有左孩子及下标是否越界
  3. 确定左孩子或者右孩子,谁是最小孩子
    1.右孩子不存在
    2.比较array[left] 和 array[right] 值的大小,选择小的为min
  4. 比较当前值和最小值
  5. 否则,交换当前和最小值
  6. 然后因为min 位置的堆的性质可能被破坏,向下重复以上过程

  操作入队列

  1. 首先按尾插方式放入数组
  2. 比较它和双亲的值的大小,如果双亲值大,则满足堆的性质,插入结束
  3. 否则,交换它和双亲的位置的值,重新进行2.3步骤
  4. 直到根结点

代码实现如下:

public class MyPriorityQueue {

   public int[] elem;
   public int usedSize;

   public MyPriorityQueue() {
       this.elem = new int[10];
   }


   // 创建大根堆
   public void adjustDown(int parent, int len) {

       int child = 2 * parent + 1;

       while (child < len) {

           // 获取子节点最大值的下标
           if (child + 1 < len && this.elem[child] < this.elem[child + 1]) {
               child++;
           }

           if (this.elem[child] > this.elem[parent]) {
               int tmp = this.elem[child];
               this.elem[child] = this.elem[parent];
               this.elem[parent] = tmp;

               parent = child;
               child = 2 * parent + 1;
           } else {
               break;
           }
       }
   }

   public void createHeap(int[] array) {

       for (int i = 0; i < array.length; i++) {
           this.elem[i] = array[i];
           this.usedSize++;
       }

       for (int p = (this.usedSize - 1 - 1) / 2; p >= 0; p--) {
           adjustDown(p, this.usedSize);
       }

   }
   // 入堆
   public void push(int key) {

       if (isFull()) {
           // 扩充容量
           this.elem = Arrays.copyOf(this.elem, this.elem.length * 2);
       }

       this.elem[this.usedSize] = key;
       this.usedSize++;

       adjustUp(this.usedSize - 1);

   }

   public boolean isFull() {
       return this.usedSize == this.elem.length;
   }

   public boolean isEmpty() {
       return this.usedSize == 0;
   }

   // 出堆(删除)
   public void pop() throws UnsupportedOperationException {

       if (isEmpty()) {
           throw new UnsupportedOperationException("队列为空!");
       }

       if (isFull()) {
           return;
       }

       int tmp = this.elem[0];
       this.elem[0] = this.elem[this.usedSize - 1];
       this.elem[this.usedSize - 1] = tmp;

       this.usedSize--;
       adjustDown(0, this.usedSize);
   }

   // 出堆(不删除)
   public int getTop() throws UnsupportedOperationException {
       if (isEmpty()) {
           throw new UnsupportedOperationException("队列为空!");
       }

       return this.elem[0];
   }
 }

以上是关于优先级队列(堆)的主要内容,如果未能解决你的问题,请参考以下文章

最小堆(优先队列)基本概念,即一个完整建立,插入,删除代码

优先队列的实现(最小堆)

优先级队列总结

Java集合与数据结构——优先级队列(堆)

数据结构 Java数据结构 ---- 堆(优先级队列)

数据结构--优先队列(堆排序)