原文: https://www.programiz.com/dsa/priority-queue

在本教程中,您将学习什么是优先队列。 另外,您还将找到 C,C++ ,Java 和 Python 中优先队列操作的工作示例。

优先队列是一种特殊的队列,其中每个元素都与一个优先级相关联,并根据其优先级进行服务。 如果出现具有相同优先级的元素,则会根据其在队列中的顺序为其提供服务。

通常,元素本身的值被认为用于分配优先级。

例如:具有最高值的元素被视为最高优先级元素。 但是,在其他情况下,我们可以将具有最低值的元素视为最高优先级元素。 在其他情况下,我们可以按需设置优先级。

优先队列 - 图1

优先级最高的元素先出队


优先队列与队列有何不同?

在队列中,实现先进先出规则,而在优先队列中,基于优先级删除值。 优先级最高的元素将首先被删除。


优先队列的实现

可以使用数组,链表,堆数据结构或二叉搜索树来实现优先队列。 在这些数据结构中,堆数据结构提供了优先队列的有效实现。

下面给出优先队列的不同实现的比较分析。

获取 插入 删除
链表 O(1) O(n) O(1)
二叉堆 O(1) O(log n) O(log n)
二叉搜索树 O(1) O(log n) O(log n)

优先队列操作

优先队列的基本操作是插入,删除和查看元素。

在研究优先队列之前,请参考堆数据结构,以更好地了解二叉堆,因为该二叉堆用于实现本文中的优先队列。


从优先队列插入元素

通过以下步骤将元素插入优先队列(最大堆)。

  1. 在树的末尾插入新元素。
    优先队列 - 图2
    在队列的末尾插入元素

  2. 对树建堆。
    优先队列 - 图3
    插入后堆

将元素插入优先队列的算法(最大堆)

  1. If there is no node,
  2. create a newNode.
  3. else (a node is already present)
  4. insert the newNode at the end (last node from left to right.)
  5. heapify the array

对于最小堆,对上述算法进行了修改,以使parentNode始终小于newNode


从优先队列中删除元素

从优先队列(最大堆)中删除元素的操作如下:

  1. 选择要删除的元素。
    优先队列 - 图4
    选择要删除的元素

  2. 将其与最后一个元素交换。
    优先队列 - 图5
    与最后一个叶节点元素
    交换

  3. 删除最后一个元素。
    优先队列 - 图6
    删除最后一个元素/叶子

  4. 对树建堆。
    优先队列 - 图7
    堆处理队列

删除优先队列中元素的算法(最大堆)

  1. If nodeToBeDeleted is the leafNode
  2. remove the node
  3. Else swap nodeToBeDeleted with the lastLeafNode
  4. remove noteToBeDeleted
  5. heapify the array

对于最小堆,对上述算法进行了修改,以使childNodes均小于currentNode


从优先队列中窥视(查找最大值/最小值)

窥视操作从最大堆中返回最大元素,或者从最小堆中返回最小元素,而不删除节点。

对于最大堆和最小堆

  1. return rootNode

从优先队列中提取最大/最小

从最大堆中删除节点后,Extract-Max返回具有最大值的节点,而从最小堆中删除节点后,Extract-Min返回具有最小值的节点。


Python,Java,C/C++ 示例

  1. # Max-Heap data structure in Python
  2. # Function to heapify the tree
  3. def heapify(arr, n, i):
  4. # Find the largest among root, left child and right child
  5. largest = i
  6. l = 2 * i + 1
  7. r = 2 * i + 2
  8. if l < n and arr[i] < arr[l]:
  9. largest = l
  10. if r < n and arr[largest] < arr[r]:
  11. largest = r
  12. # Swap and continue heapifying if root is not largest
  13. if largest != i:
  14. arr[i], arr[largest] = arr[largest], arr[i]
  15. heapify(arr, n, largest)
  16. # Function to insert an element into the tree
  17. def insert(array, newNum):
  18. size = len(array)
  19. if size == 0:
  20. array.append(newNum)
  21. else:
  22. array.append(newNum)
  23. for i in range((size // 2) - 1, -1, -1):
  24. heapify(array, size, i)
  25. # Function to delete an element from the tree
  26. def deleteNode(array, num):
  27. size = len(array)
  28. i = 0
  29. for i in range(0, size):
  30. if num == array[i]:
  31. break
  32. array[i], array[size - 1] = array[size - 1], array[i]
  33. array.remove(size - 1)
  34. for i in range((len(array) // 2) - 1, -1, -1):
  35. heapify(array, len(array), i)
  36. arr = []
  37. insert(arr, 3)
  38. insert(arr, 4)
  39. insert(arr, 9)
  40. insert(arr, 5)
  41. insert(arr, 2)
  42. print ("Max-Heap array: " + str(arr))
  43. deleteNode(arr, 4)
  44. print("After deleting an element: " + str(arr))
  1. // Max-Heap data structure in Java
  2. import java.util.ArrayList;
  3. class Heap {
  4. // Function to heapify the tree
  5. void heapify(ArrayList<Integer> hT, int i) {
  6. int size = hT.size();
  7. // Find the largest among root, left child and right child
  8. int largest = i;
  9. int l = 2 * i + 1;
  10. int r = 2 * i + 2;
  11. if (l < size && hT.get(l) > hT.get(largest))
  12. largest = l;
  13. if (r < size && hT.get(r) > hT.get(largest))
  14. largest = r;
  15. // Swap and continue heapifying if root is not largest
  16. if (largest != i) {
  17. int temp = hT.get(largest);
  18. hT.set(largest, hT.get(i));
  19. hT.set(i, temp);
  20. heapify(hT, largest);
  21. }
  22. }
  23. // Function to insert an element into the tree
  24. void insert(ArrayList<Integer> hT, int newNum) {
  25. int size = hT.size();
  26. if (size == 0) {
  27. hT.add(newNum);
  28. } else {
  29. hT.add(newNum);
  30. for (int i = size / 2 - 1; i >= 0; i--) {
  31. heapify(hT, i);
  32. }
  33. }
  34. }
  35. // Function to delete an element from the tree
  36. void deleteNode(ArrayList<Integer> hT, int num) {
  37. int size = hT.size();
  38. int i;
  39. for (i = 0; i < size; i++) {
  40. if (num == hT.get(i))
  41. break;
  42. }
  43. int temp = hT.get(i);
  44. hT.set(i, hT.get(size - 1));
  45. hT.set(size - 1, temp);
  46. hT.remove(size - 1);
  47. for (int j = size / 2 - 1; j >= 0; j--) {
  48. heapify(hT, j);
  49. }
  50. }
  51. // Print the tree
  52. void printArray(ArrayList<Integer> array, int size) {
  53. for (Integer i : array) {
  54. System.out.print(i + " ");
  55. }
  56. System.out.println();
  57. }
  58. // Driver code
  59. public static void main(String args[]) {
  60. ArrayList<Integer> array = new ArrayList<Integer>();
  61. int size = array.size();
  62. Heap h = new Heap();
  63. h.insert(array, 3);
  64. h.insert(array, 4);
  65. h.insert(array, 9);
  66. h.insert(array, 5);
  67. h.insert(array, 2);
  68. System.out.println("Max-Heap array: ");
  69. h.printArray(array, size);
  70. h.deleteNode(array, 4);
  71. System.out.println("After deleting an element: ");
  72. h.printArray(array, size);
  73. }
  74. }
  1. // Max-Heap data structure in C
  2. #include <stdio.h>
  3. int size = 0;
  4. void swap(int *a, int *b) {
  5. int temp = *b;
  6. *b = *a;
  7. *a = temp;
  8. }
  9. // Function to heapify the tree
  10. void heapify(int array[], int size, int i) {
  11. if (size == 1) {
  12. printf("Single element in the heap");
  13. } else {
  14. // Find the largest among root, left child and right child
  15. int largest = i;
  16. int l = 2 * i + 1;
  17. int r = 2 * i + 2;
  18. if (l < size && array[l] > array[largest])
  19. largest = l;
  20. if (r < size && array[r] > array[largest])
  21. largest = r;
  22. // Swap and continue heapifying if root is not largest
  23. if (largest != i) {
  24. swap(&array[i], &array[largest]);
  25. heapify(array, size, largest);
  26. }
  27. }
  28. }
  29. // Function to insert an element into the tree
  30. void insert(int array[], int newNum) {
  31. if (size == 0) {
  32. array[0] = newNum;
  33. size += 1;
  34. } else {
  35. array[size] = newNum;
  36. size += 1;
  37. for (int i = size / 2 - 1; i >= 0; i--) {
  38. heapify(array, size, i);
  39. }
  40. }
  41. }
  42. // Function to delete an element from the tree
  43. void deleteRoot(int array[], int num) {
  44. int i;
  45. for (i = 0; i < size; i++) {
  46. if (num == array[i])
  47. break;
  48. }
  49. swap(&array[i], &array[size - 1]);
  50. size -= 1;
  51. for (int i = size / 2 - 1; i >= 0; i--) {
  52. heapify(array, size, i);
  53. }
  54. }
  55. // Print the array
  56. void printArray(int array[], int size) {
  57. for (int i = 0; i < size; ++i)
  58. printf("%d ", array[i]);
  59. printf("\n");
  60. }
  61. // Driver code
  62. int main() {
  63. int array[10];
  64. insert(array, 3);
  65. insert(array, 4);
  66. insert(array, 9);
  67. insert(array, 5);
  68. insert(array, 2);
  69. printf("Max-Heap array: ");
  70. printArray(array, size);
  71. deleteRoot(array, 4);
  72. printf("After deleting an element: ");
  73. printArray(array, size);
  74. }
  1. // Max-Heap data structure in C++
  2. #include <iostream>
  3. #include <vector>
  4. using namespace std;
  5. // Function to swap position of two elements
  6. void swap(int *a, int *b) {
  7. int temp = *b;
  8. *b = *a;
  9. *a = temp;
  10. }
  11. // Function to heapify the tree
  12. void heapify(vector<int> &hT, int i) {
  13. int size = hT.size();
  14. // Find the largest among root, left child and right child
  15. int largest = i;
  16. int l = 2 * i + 1;
  17. int r = 2 * i + 2;
  18. if (l < size && hT[l] > hT[largest])
  19. largest = l;
  20. if (r < size && hT[r] > hT[largest])
  21. largest = r;
  22. // Swap and continue heapifying if root is not largest
  23. if (largest != i) {
  24. swap(&hT[i], &hT[largest]);
  25. heapify(hT, largest);
  26. }
  27. }
  28. // Function to insert an element into the tree
  29. void insert(vector<int> &hT, int newNum) {
  30. int size = hT.size();
  31. if (size == 0) {
  32. hT.push_back(newNum);
  33. } else {
  34. hT.push_back(newNum);
  35. for (int i = size / 2 - 1; i >= 0; i--) {
  36. heapify(hT, i);
  37. }
  38. }
  39. }
  40. // Function to delete an element from the tree
  41. void deleteNode(vector<int> &hT, int num) {
  42. int size = hT.size();
  43. int i;
  44. for (i = 0; i < size; i++) {
  45. if (num == hT[i])
  46. break;
  47. }
  48. swap(&hT[i], &hT[size - 1]);
  49. hT.pop_back();
  50. for (int i = size / 2 - 1; i >= 0; i--) {
  51. heapify(hT, i);
  52. }
  53. }
  54. // Print the tree
  55. void printArray(vector<int> &hT) {
  56. for (int i = 0; i < hT.size(); ++i)
  57. cout << hT[i] << " ";
  58. cout << "\n";
  59. }
  60. // Driver code
  61. int main() {
  62. vector<int> heapTree;
  63. insert(heapTree, 3);
  64. insert(heapTree, 4);
  65. insert(heapTree, 9);
  66. insert(heapTree, 5);
  67. insert(heapTree, 2);
  68. cout << "Max-Heap array: ";
  69. printArray(heapTree);
  70. deleteNode(heapTree, 4);
  71. cout << "After deleting an element: ";
  72. printArray(heapTree);
  73. }

优先队列应用

优先队列的一些应用是:

  • Dijkstra 算法
  • 用于实现栈
  • 用于操作系统中的负载平衡和中断处理
  • 用于霍夫曼代码中的数据压缩