一、 優先隊列的概述
在前面的數據結構(三):線性表-棧,隊列中記錄到,隊列是先進先出的結構,元素在隊列末端添加,在隊列前頭刪除,若使用該隊列的數據結構,則當要找出隊列中的最大最小值時,需要遍歷隊列
對每個元素做比較后得出,這樣在實際的生產應用中效率是很低的,這時就需要有一種隊列,能快捷的獲取隊列中的最大或最小值,叫做優先隊列。
使用優先隊列保存數據元素,能快速的獲取隊列的最大或最小值,比如計算機中有多個排隊的任務,但是需要按照優先級一一執行,此時優先隊列的優勢便得到了體現,在前一章對堆的記錄中
我們發現堆能快速的找到最大或最小值並刪除,符合優先隊列的應用場景,因此本章我們使用堆來實現最大,最小優先隊列和索引優先隊列
二、 最小優先隊列
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 + ","); }
} } |