• 数据结构(八):优先队列-最大最小优先


     

    一、 优先队列的概述

      在前面的数据结构(三):线性表-栈,队列中记录到,队列是先进先出的结构,元素在队列末端添加,在队列前头删除,若使用该队列的数据结构,则当要找出队列中的最大最小值时,需要遍历队列

      对每个元素做比较后得出,这样在实际的生产应用中效率是很低的,这时就需要有一种队列,能快捷的获取队列中的最大或最小值,叫做优先队列。

      使用优先队列保存数据元素,能快速的获取队列的最大或最小值,比如计算机中有多个排队的任务,但是需要按照优先级一一执行,此时优先队列的优势便得到了体现,在前一章对堆的记录中

      我们发现堆能快速的找到最大或最小值并删除,符合优先队列的应用场景,因此本章我们使用堆来实现最大,最小优先队列和索引优先队列

       

    二、 最小优先队列

      1、最小优先队列实际就是一个小顶堆,即每次插入堆中的元素,都存储至堆末端,通过上浮操作比较,小于父节点则和父节点交换元素,直到根结点为止,这样就形成了一个小顶堆。

      2、在获取最小值时,由于堆是数组的结构,只需获取根结点的值,即数组下标为1的值即可。

      3、获取最小值并删除,则可以交换根结点和尾结点,之后删除尾结点,并对根结点进行下沉操作,保证每个父节点都小于两个左右子树即可

       

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

    // 初始化堆

    private T[] items;

    // 初始化个数

    private int N;

    /**

     * 返回优先队列大小

     *

     * @return

     */

    public int size() {

           return N;

    }

    /**

     * 队列是否为空

     *

     * @return

     */

    public boolean isEmpty() {

           return N==0;

    }

    /**

     * 构造方法,传入堆的初始大小

     *

     * @param size

     */

    public MinPriorityQueue(int size) {

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

           N = 0;

    }

    /**

     * 判断堆中索引i处的值是否小于j处的值

     *

     * @param i

     * @param j

     * @return

     */

    private boolean bigger(int i, int j) {

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

    }

    /**

     * 元素位置的交换

     *

     * @param col

     * @param i

     * @param j

     */

    private void switchPos(int i, int j) {

           T temp = items[i];

           items[i] = items[j];

           items[j] = temp;

    }

    /**

     * 删除堆中最大的元素,并且返回这个元素

     *

     * @return

     */

    public T delMin() {

           // 获取根结点最大值

           T minValue = items[1];

           // 交换根结点和尾结点

           switchPos(1, N);

           // 尾结点置空

           items[N] = null;

           // 堆数量减1

           N--;

           // 根结点下沉

           sink(1);

           return minValue;

    }

    /**

     * 往堆中插入一个元素t

     *

     * @param t

     */

    public void insert(T t) {

           items[++N] = t;

           swim(N);

    }

    /**

     * 使用上浮算法,使堆中索引k处的值能够处于一个正确的位置

     *

     * @param k

     */

    private void swim(int k) {

           while (k > 1) {

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

                         switchPos(k, k /2);

                  }

                  k = k / 2;

           }

    }

    /**

     * 使用下沉算法,使堆中索引k处的值能够处于一个正确的位置

     *

     * @param k

     */

    private void sink(int k) {

           while (2 * k <= N) {

                  int min;

                  // 存在右子结点的情况

                  if (2 * k + 1 <= N) {

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

                                min = 2 * k + 1;

                         } else {

                                min = 2 * k;

                         }

                  } else {

                         min = 2 * k;

                  }

                  // 当前结点不比左右子树结点的最小值小,则退出

                  if (bigger(min, k)) {

                         break;

                  }

                  switchPos(k, min);

                  k = min;

           }

    }

    public static void main(String[] args) {

           String[] arr = { "S", "O", "R", "T", "E", "X", "A", "M", "P", "L", "E" };

           MinPriorityQueue<String> minpq = new MinPriorityQueue<>(20);

           for (String s : arr) {

                  minpq.insert(s);

           }

           String del;

           while (!minpq.isEmpty()) {

                  del = minpq.delMin();

                  System.out.print(minpq.size());

                  System.out.println(del + ",");

           }

    }

    }


    三、
    最大优先队列

      1、最大优先队列实际就是一个大顶堆,即每次插入堆中的元素,都存储至堆末端,通过上浮操作比较,大于父节点则和父节点交换元素,直到根结点为止,这样就形成了一个大顶堆。

      2、在获取最大值时,由于堆是数组的结构,只需获取根结点的值,即数组下标为1的值即可。

      3、获取最大值并删除,则可以交换根结点和尾结点,之后删除尾结点,并对根结点进行下沉操作,保证每个父节点都大于两个左右子树即可

       

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

    // 初始化堆

    private T[] items;

    // 初始化个数

    private int N;

    /**

     * 返回优先队列大小

     *

     * @return

     */

    public int size() {

           return N;

    }

    /**

     * 队列是否为空

     *

     * @return

     */

    public boolean isEmpty() {

           return N == 0;

    }

    /**

     * 构造方法,传入堆的初始大小

     *

     * @param size

     */

    public MaxPriorityQueue(int size) {

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

           N = 0;

    }

    /**

     * 判断堆中索引i处的值是否小于j处的值

     *

     * @param i

     * @param j

     * @return

     */

    private boolean bigger(int i, int j) {

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

    }

    /**

     * 元素位置的交换

     *

     * @param col

     * @param i

     * @param j

     */

    private void switchPos(int i, int j) {

           T temp = items[i];

           items[i] = items[j];

           items[j] = temp;

    }

    /**

     * 删除堆中最大的元素,并且返回这个元素

     *

     * @return

     */

    public T delMax() {

           // 获取根结点最大值

           T maxValue = items[1];

           // 交换根结点和尾结点

           switchPos(1, N);

           // 尾结点置空

           items[N] = null;

           // 堆数量减1

           N--;

           // 根结点下沉

           sink(1);

           return maxValue;

    }

    /**

     * 往堆中插入一个元素t

     *

     * @param t

     */

    public void insert(T t) {

           items[++N] = t;

           swim(N);

    }

    /**

     * 使用上浮算法,使堆中索引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 max;

                  // 存在右子结点的情况

                  if (2 * k + 1 <= N) {

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

                                max = 2 * k;

                         } else {

                                max = 2 * k + 1;

                         }

                  } else {

                         max = 2 * k;

                  }

                  // 当前结点比左右子树的最大值大,则退出

                  if (bigger(k, max)) {

                         break;

                  }

                  switchPos(k, max);

                  k = max;

           }

    }

    public static void main(String[] args) {

           String[] arr = { "S", "O", "R", "T", "E", "X", "A", "M", "P", "L", "E" };

           MaxPriorityQueue<String> maxpq = new MaxPriorityQueue<>(20);

           for (String s : arr) {

                  maxpq.insert(s);

           }

           System.out.println(maxpq.size());

           String del;

           while (!maxpq.isEmpty()) {

                  del = maxpq.delMax();

                  System.out.print(del + ",");

           }

    }

    }

  • 相关阅读:
    压缩打包linux 文件压缩解压命令Strut2教程java教程
    【leetcode】Valid Parentheses
    指向数据个人对指针的理解,欢迎大家批评Strut2教程java教程
    UML中的用例图
    Extjs4中组件的查找方式
    Extjs中选择组件、选择元素的方法
    [转载]C 内存管理详解
    C开发机顶盒实战代码之队列
    C机顶盒开发实战常用初始化类型:数组、结构、指针
    [转载]C语言链表的建立、插入和删除
  • 原文地址:https://www.cnblogs.com/jiyukai/p/14056606.html
Copyright © 2020-2023  润新知