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

在本教程中,您将学习什么是循环队列。 此外,您还将发现在 C,C++ ,Java 和 Python 中实现循环队列。

循环队列避免了使用数组实现的常规队列中的空间浪费。

循环队列 - 图1

循环队列

如您在上图中所看到的,在进行一些入队和出队后,队列的大小已减小。

只有当所有元素都已出队后,才能在重置队列后使用索引 0 和 1。


循环队列如何工作

循环队列通过循环递增的过程来工作,即,当我们尝试递增任何变量并到达队列的末尾时,我们通过对队列大小进行模除从队列的开头开始。

  1. if REAR + 1 == 5 (overflow!), REAR = (REAR + 1)%5 = 0 (start of queue)

循环队列 - 图2

循环队列表示

队列操作如下:

  • 两个称为FRONTREAR的指针用于跟踪队列中的第一个和最后一个元素。
  • 初始化队列时,我们将FRONTREAR的值设置为 -1。
  • 在对元素进行排队时,我们循环增加REAR索引的值,并将新元素放置在REAR指向的位置。
  • 在元素出队时,我们返回FRONT指向的值,并循环增加FRONT索引。
  • 在入队之前,我们检查队列是否已满。
  • 在出队之前,我们检查队列是否已经为空。
  • 当对第一个元素进行排队时,我们将FRONT的值设置为 0。
  • 使最后一个元素出队时,我们将FRONTREAR的值重置为 -1。

但是,检查完整队列还有另外一种新情况:

  • 情况 1:FRONT = 0 && REAR == SIZE - 1
  • 情况 2:FRONT = REAR + 1

第二种情况发生在REAR由于循环增量而从 0 开始且其值仅比FRONT小 1 时,队列已满。

循环队列 - 图3

循环队列的原理


Python,Java 和 C/C++ 示例

最常见的队列实现是使用数组,但是也可以使用列表来实现。

  1. # Circular Queue implementation in Python
  2. class MyCircularQueue(object):
  3. def __init__(self, k):
  4. self.maxlen = k
  5. self.currlen = 0
  6. self.queue = [None] * k
  7. self.head = -1
  8. self.tail = -1
  9. # Insert an element into the circular queue
  10. def enQueue(self, value):
  11. if self.isFull():
  12. return False
  13. tail = (self.tail + 1) % self.maxlen
  14. self.queue[tail] = value
  15. self.tail = tail
  16. self.currlen += 1
  17. if self.currlen == 1:
  18. self.head = 0
  19. return True
  20. # Delete an element from the circular queue
  21. def deQueue(self):
  22. if self.isEmpty():
  23. return False
  24. self.head = (self.head + 1) % self.maxlen
  25. self.currlen -= 1
  26. if self.isEmpty():
  27. self.head = -1
  28. self.tail = -1
  29. return True
  30. # Get the front item from the queue
  31. def Front(self):
  32. if self.isEmpty():
  33. return -1
  34. return self.queue[self.head]
  35. # Get the last item from the queue
  36. def Rear(self):
  37. if self.isEmpty():
  38. return -1
  39. return self.queue[self.tail]
  40. # Checks whether the circular queue is empty or not
  41. def isEmpty(self):
  42. return self.currlen == 0
  43. # Checks whether the circular queue is full or not
  44. def isFull(self):
  45. return self.currlen == self.maxlen
  46. # Display the queue
  47. def Display(self):
  48. for i in range(self.head, self.tail):
  49. print(self.queue[i], end=" ")
  50. # Your MyCircularQueue object will be instantiated and called as such:
  51. obj = MyCircularQueue(5)
  52. obj.enQueue(1)
  53. obj.enQueue(2)
  54. obj.enQueue(3)
  55. obj.enQueue(4)
  56. obj.enQueue(5)
  57. print("Initial array")
  58. print(obj.Display())
  59. print("After removing an element")
  60. obj.deQueue()
  61. obj.Display()
  1. // Circular Queue implementation in Java
  2. public class CQueue {
  3. int SIZE = 5; // Size of Circular Queue
  4. int front, rear;
  5. int items[] = new int[SIZE];
  6. CQueue() {
  7. front = -1;
  8. rear = -1;
  9. }
  10. // Check if the queue is full
  11. boolean isFull() {
  12. if (front == 0 && rear == SIZE - 1) {
  13. return true;
  14. }
  15. if (front == rear + 1) {
  16. return true;
  17. }
  18. return false;
  19. }
  20. // Check if the queue is empty
  21. boolean isEmpty() {
  22. if (front == -1)
  23. return true;
  24. else
  25. return false;
  26. }
  27. // Adding an element
  28. void enQueue(int element) {
  29. if (isFull()) {
  30. System.out.println("Queue is full");
  31. } else {
  32. if (front == -1)
  33. front = 0;
  34. rear = (rear + 1) % SIZE;
  35. items[rear] = element;
  36. System.out.println("Inserted " + element);
  37. }
  38. }
  39. // Removing an element
  40. int deQueue() {
  41. int element;
  42. if (isEmpty()) {
  43. System.out.println("Queue is empty");
  44. return (-1);
  45. } else {
  46. element = items[front];
  47. if (front == rear) {
  48. front = -1;
  49. rear = -1;
  50. } /* Q has only one element, so we reset the queue after deleting it. */
  51. else {
  52. front = (front + 1) % SIZE;
  53. }
  54. return (element);
  55. }
  56. }
  57. void display() {
  58. /* Function to display status of Circular Queue */
  59. int i;
  60. if (isEmpty()) {
  61. System.out.println("Empty Queue");
  62. } else {
  63. System.out.println("Front -> " + front);
  64. System.out.println("Items -> ");
  65. for (i = front; i != rear; i = (i + 1) % SIZE)
  66. System.out.print(items[i] + " ");
  67. System.out.println(items[i]);
  68. System.out.println("Rear -> " + rear);
  69. }
  70. }
  71. public static void main(String[] args) {
  72. CQueue q = new CQueue();
  73. // Fails because front = -1
  74. q.deQueue();
  75. q.enQueue(1);
  76. q.enQueue(2);
  77. q.enQueue(3);
  78. q.enQueue(4);
  79. q.enQueue(5);
  80. // Fails to enqueue because front == 0 && rear == SIZE - 1
  81. q.enQueue(6);
  82. q.display();
  83. int elem = q.deQueue();
  84. if (elem != -1) {
  85. System.out.println("Deleted Element is " + elem);
  86. }
  87. q.display();
  88. q.enQueue(7);
  89. q.display();
  90. // Fails to enqueue because front == rear + 1
  91. q.enQueue(8);
  92. }
  93. }
  1. // Circular Queue implementation in C
  2. #include <stdio.h>
  3. #define SIZE 5
  4. int items[SIZE];
  5. int front = -1, rear = -1;
  6. // Check if the queue is full
  7. int isFull() {
  8. if ((front == rear + 1) || (front == 0 && rear == SIZE - 1)) return 1;
  9. return 0;
  10. }
  11. // Check if the queue is empty
  12. int isEmpty() {
  13. if (front == -1) return 1;
  14. return 0;
  15. }
  16. // Adding an element
  17. void enQueue(int element) {
  18. if (isFull())
  19. printf("\n Queue is full!! \n");
  20. else {
  21. if (front == -1) front = 0;
  22. rear = (rear + 1) % SIZE;
  23. items[rear] = element;
  24. printf("\n Inserted -> %d", element);
  25. }
  26. }
  27. // Removing an element
  28. int deQueue() {
  29. int element;
  30. if (isEmpty()) {
  31. printf("\n Queue is empty !! \n");
  32. return (-1);
  33. } else {
  34. element = items[front];
  35. if (front == rear) {
  36. front = -1;
  37. rear = -1;
  38. }
  39. // Q has only one element, so we reset the
  40. // queue after dequeing it. ?
  41. else {
  42. front = (front + 1) % SIZE;
  43. }
  44. printf("\n Deleted element -> %d \n", element);
  45. return (element);
  46. }
  47. }
  48. // Display the queue
  49. void display() {
  50. int i;
  51. if (isEmpty())
  52. printf(" \n Empty Queue\n");
  53. else {
  54. printf("\n Front -> %d ", front);
  55. printf("\n Items -> ");
  56. for (i = front; i != rear; i = (i + 1) % SIZE) {
  57. printf("%d ", items[i]);
  58. }
  59. printf("%d ", items[i]);
  60. printf("\n Rear -> %d \n", rear);
  61. }
  62. }
  63. int main() {
  64. // Fails because front = -1
  65. deQueue();
  66. enQueue(1);
  67. enQueue(2);
  68. enQueue(3);
  69. enQueue(4);
  70. enQueue(5);
  71. // Fails to enqueue because front == 0 && rear == SIZE - 1
  72. enQueue(6);
  73. display();
  74. deQueue();
  75. display();
  76. enQueue(7);
  77. display();
  78. // Fails to enqueue because front == rear + 1
  79. enQueue(8);
  80. return 0;
  81. }
  1. // Circular Queue implementation in C++
  2. #include <iostream>
  3. #define SIZE 5 /* Size of Circular Queue */
  4. using namespace std;
  5. class Queue {
  6. private:
  7. int items[SIZE], front, rear;
  8. public:
  9. Queue() {
  10. front = -1;
  11. rear = -1;
  12. }
  13. // Check if the queue is full
  14. bool isFull() {
  15. if (front == 0 && rear == SIZE - 1) {
  16. return true;
  17. }
  18. if (front == rear + 1) {
  19. return true;
  20. }
  21. return false;
  22. }
  23. // Check if the queue is empty
  24. bool isEmpty() {
  25. if (front == -1)
  26. return true;
  27. else
  28. return false;
  29. }
  30. // Adding an element
  31. void enQueue(int element) {
  32. if (isFull()) {
  33. cout << "Queue is full";
  34. } else {
  35. if (front == -1) front = 0;
  36. rear = (rear + 1) % SIZE;
  37. items[rear] = element;
  38. cout << endl
  39. << "Inserted " << element << endl;
  40. }
  41. }
  42. // Removing an element
  43. int deQueue() {
  44. int element;
  45. if (isEmpty()) {
  46. cout << "Queue is empty" << endl;
  47. return (-1);
  48. } else {
  49. element = items[front];
  50. if (front == rear) {
  51. front = -1;
  52. rear = -1;
  53. }
  54. // Q has only one element,
  55. // so we reset the queue after deleting it.
  56. else {
  57. front = (front + 1) % SIZE;
  58. }
  59. return (element);
  60. }
  61. }
  62. void display() {
  63. // Function to display status of Circular Queue
  64. int i;
  65. if (isEmpty()) {
  66. cout << endl
  67. << "Empty Queue" << endl;
  68. } else {
  69. cout << "Front -> " << front;
  70. cout << endl
  71. << "Items -> ";
  72. for (i = front; i != rear; i = (i + 1) % SIZE)
  73. cout << items[i];
  74. cout << items[i];
  75. cout << endl
  76. << "Rear -> " << rear;
  77. }
  78. }
  79. };
  80. int main() {
  81. Queue q;
  82. // Fails because front = -1
  83. q.deQueue();
  84. q.enQueue(1);
  85. q.enQueue(2);
  86. q.enQueue(3);
  87. q.enQueue(4);
  88. q.enQueue(5);
  89. // Fails to enqueue because front == 0 && rear == SIZE - 1
  90. q.enQueue(6);
  91. q.display();
  92. int elem = q.deQueue();
  93. if (elem != -1)
  94. cout << endl
  95. << "Deleted Element is " << elem;
  96. q.display();
  97. q.enQueue(7);
  98. q.display();
  99. // Fails to enqueue because front == rear + 1
  100. q.enQueue(8);
  101. return 0;
  102. }

循环队列复杂度

对于(数组实现),循环队列的入队和出队操作的复杂度为O(1)


循环队列应用

  • CPU 调度
  • 内存管理
  • 交通管理