zoukankan      html  css  js  c++  java
  • 数据结构(八):优先队列-索引优先

     

    一、 索引优先队列

      上一章节的数据结构(八):优先队列-大小优先中,能够快速的从队列中取出最大最小值并删除,但有个缺点,就是无法通过索引快速的找到某个值,并且修改它,对于能快速根据索引查找到值的需求

      我们使用索引优先队列来实现。

    二、 最小索引优先队列思路

      步骤一:实现索引优先队列,直观的想法是对数据元素添加对应的key,方便通过key找到value,由于优先队列我们使用数组实现,因此可以使用索引-值的方式来表示,如下图:

      items[]:{ "S", "O", "R", "T", "E", "X", "A", "M", "P", "L", "E" }

       

      这样我们便能通过items[i]获取到值

      步骤二:

      步骤一将元素存储至堆数组后,发现不符合堆有序,此时若对items数组进行堆有序调整,则会破坏元素在items的下标,再通过items[i]获取时会有问题,此时我们引入一个辅助数组pq[]

      pq的存放元素在 items中的索引,对堆进行有序处理时,只需处理pq[i]即可:

      有序后的堆:

       

       

      此时的pq数组即是一个有序堆

      步骤三:

      通过步骤二的调整后,我们对堆有序的调整,只需通过pq进行调整,items元素保持不变,当我们做出items[0]=J的操作后,只需通过遍历pq数组,对pq[9]做上浮和下沉调整即可,保证pq堆有序

      但在数据比较大的场景下,上述的遍历找到pq[i]的成本就变得很高,此时我们引入另一个辅助数组qp[],qp的存在是为了更快找到pq中值对应的items的索引,此时我们可以对pq做一个倒转

      及qp的索引是pq的值,qp的值是pq的索引,见下图:

       

      有了qp数组后,当我们做出items[0]=J的操作后,只需通过qp[0]获取到9,再去对pq[9]做上浮和下沉处理,及可在修改队列元素的同时,又保证堆有序。

    三、 代码实现

      如下代码基于如上三个步骤实现了索引最小优先队列:

    /**

     * 索引最小优先队列

     *

     * @author jiyukai

     * @param <T>

     */

    public class IndexMinPriorityQueue<T extends Comparable<T>> {

           // 存储具体元素的堆

           private T[] items;

           // 保存每个元素在items中的索引,pq需要堆有序

           private int[] pq;

           // 保存pq数组索引和值的逆序

           private int[] qp;

           // 堆中元素的个数

           private int N;

           /**

            * 初始化索引优先队列的大小

            *

            * @param size

            */

           public IndexMinPriorityQueue(int size) {

                  items = (T[]) new Comparable[size + 1];

                  N = 0;

                  pq = new int[size + 1];

                  qp = new int[size + 1];

                  for (int i = 0; i < qp.length; i++) {

                         qp[i] = -1;

                  }

           }

           /**

            * 优先队列大小

            *

            * @return

            */

           public int size() {

                  return N;

           }

           /**

            * 是否为空

            *

            * @return

            */

           public boolean isEmpty() {

                  return N == 0;

           }

           /**

            * 元素大小比较

            *

            * @param i

            * @param j

            * @return

            */

           public boolean bigger(int i, int j) {

                  return items[i].compareTo(items[j]) > 0;

           }

           /**

            * 位置交换

            *

            * @param i

            * @param j

            */

           private void switchPos(int i, int j) {

                  int temp = pq[i];

                  pq[i] = pq[j];

                  pq[j] = temp;

                  // 修改qp

                  qp[pq[i]] = i;

                  qp[pq[j]] = j;

           }

           /**

            * 判断k位置对应的元素是否存在

            *

            * @param k

            * @return

            */

           public boolean contains(int k) {

                  return qp[k] != -1;

           }

           /**

            * 最小元素的索引

            *

            * @return

            */

           public int minIndex() {

                  return pq[1];

           }

           /**

            * i位置处插入元素t

            *

            * @param i

            * @param t

            * @throws Exception

            */

           public void insert(int i, T t) throws Exception {

                  // 判断位置i处是否存在元素t

                  if (contains(i)) {

                         throw new Exception(i + "位置处已有元素" + t);

                  }

                  // item的i处插入t

                  items[i] = t;

                  // 元素个数+1

                  N++;

                  // 插入到最后一个元素,因此pq的N位置处为item的i

                  pq[N] = i;

                  // 修改qp的i位置处为N

                  qp[i] = N;

                  // 上浮处理N,让堆有序

                  swim(N);

           }

           /**

            * 删除最小的元素并返回这个元素关联的索引

            *

            * @return

            */

           public int delMin() {

                  // 获取items中最小的元素的索引

                  int min = pq[1];

                  // 交换最小元素和N位置处的元素

                  switchPos(1, N);

                  // 删除qp

                  qp[pq[N]] = -1;

                  // 删除pq

                  pq[N] = -1;

                  // N位置处的元素置空,即删除掉最小元素

                  items[min] = null;

                  // 元素个数减1

                  N--;

                  // 对1位置处的元素进行下沉处理

                  sink(1);

                  return min;

           }

           /**

            * 删除索引i关联的元素

            *

            * @param i

            */

           public void delete(int i) {

                  // 获取items i位置的元素

                  int index = pq[i];

                  // 交换最小元素和N位置处的元素

                  switchPos(index, N);

                  // 删除qp

                  qp[pq[N]] = -1;

                  // 删除pq

                  pq[N] = -1;

                  // N位置处的元素置空,即删除掉最小元素

                  items[i] = null;

                  // 元素个数减1

                  N--;

                  // 对i位置处的元素进行下沉处理

                  sink(index);

                 

                  // 对i位置处的元素进行上浮处理

                  swim(index);

           }

           /**

            * 把索引i处的元素修改为t

            *

            * @param i

            * @param t

            */

           public void changeItem(int i, T t) {

                  //修改items中i位置处的元素为t

                  items[i] = t;

                  //获取i位置处元素在pq中的索引

                  int k = pq[i];

                  //上浮

                  swim(k);

                  //下沉

                  sink(k);

           }

           /**

            * 上浮k位置处的元素

            *

            * @param k

            */

           private void swim(int k) {

                  while(k>1) {

                         if(bigger(k, k/2)) {

                                switchPos(k, k/2);

                         }

                        

                         k = k/2;

                  }

           }

           /**

            * 下沉k位置处的元素

            *

            * @param k

            */

           private void sink(int k) {

                  while(2 * k <= N) {

                         int min = 2 * k;

                         if(bigger(2*k, 2*k+1)) {

                                min = 2*k+1;

                         }

                        

                         if(bigger(min,k)) {

                                break;

                         }

                        

                         switchPos(min, k);

                        

                         k = min;

                  }

           }

    }

  • 相关阅读:
    块数据加密模式
    "jobTracker is not yet running"(hadoop 配置)
    平衡搜索树
    Programming Assignment 3: Collinear Points
    Programming Assignment 2: Randomized Queues and Deques
    Programming Assignment 1: Percolation
    1007. Maximum Subsequence Sum (25)
    Link List
    1081. Rational Sum (20)
    strassen algorithm
  • 原文地址:https://www.cnblogs.com/jiyukai/p/14056619.html
Copyright © 2011-2022 走看看