使用循环数组实现双端队列

2024年8月28日 | 阅读 12 分钟

在通过循环数组实现双端队列之前,我们先来了解一下什么是队列?

队列是一种有序的元素集合,其中新元素添加到一端,称为“队尾”,而现有元素则从另一端移除,称为“队头”。当一个元素加入队列时,它会从队尾开始,逐渐向队头移动,等待下一个元素被移除。队列中最新添加的元素必须等到它到达集合的末尾。最先进入集合的元素位于队头。FIFO,即先进先出,是这种排序方式的另一种说法。“先到先得”也是对它的另一种称呼。

操作系统使用各种不同的队列来管理计算机内的进程。下一个任务通常使用队列方法进行调度,以尽快运行程序,同时服务尽可能多的人。此外,当我们输入时,按键有时会比屏幕上的字符还要多,这是因为计算机目前正在处理其他任务。按键会排入缓冲区,稍后按正确顺序显示在屏幕上。

入队是将元素添加到队列尾部的过程,而出队是从队列头部移除元素的过程。其他操作,如查看或获取队头元素的操作,可以在不移除元素的情况下返回即将出队的下一个元素的值。

现在我们来理解双端队列。双端队列(deque,double-ended queue)是与队列功能相似的有序元素集合。它有两个端,队头和队尾,集合中的元素保持不变。双端队列的独特之处在于其对添加和移除元素的无限制性。新元素可以添加到队头或队尾。现有元素也可以从任一端移除。值得注意的是,虽然双端队列可以模仿栈和队列的许多属性,但它不强制要求这些数据结构强制执行的 LIFO(后进先出)和 FIFO(先进先出)顺序。这取决于您如何一致地使用添加和移除操作。以下是双端队列数据结构支持的各种操作:

  • insertFront(x): insertFront() 函数将在双端队列的队头插入元素 x。该函数有一个参数,表示我们要添加到双端队列数据结构队头的数据。
  • insertRear(x): insertRear() 函数将在双端队列的队尾插入元素 x。该函数有一个参数,表示我们要添加到双端队列数据结构队尾的数据。
  • deleteFront(): deleteFront() 函数将从双端队列的队头移除一个元素。
  • deleteRear(): deleteRear() 函数将从双端队列的队尾移除一个元素。
  • getFront(): getFront() 函数将返回双端队列队头的元素。
  • getRear(): getRear() 函数将返回双端队列队尾的元素。
  • isEmpty(): isEmpty() 函数将返回双端队列是否为空。
  • isFull(): isFull() 函数将返回双端队列是否已满。

Java 代码

现在,我们用 Java 编程语言编写代码,使用循环数组创建一个双端队列数据结构。

输出

上面的代码产生以下输出:

Please Choose one of the Operations::
1. To Insert Data at the Front of Deque.
2. To Insert Data at the Rear of Deque.
3. To Print Data from the Front of Deque.
4. To Print Data from the Rear of Deque.
5. To Delete Data from the Front of Deque.
6. To Delete Data from the Rear of Deque.
7. To print the Deque.
1
Enter the data:

10
Data Added Successfully.


Type [N or n] to terminate the program.
Type [Y or y] to continue the program.

y
Please Choose one of the Operations::
1. To Insert Data at the Front of Deque.
2. To Insert Data at the Rear of Deque.
3. To Print Data from the Front of Deque.
4. To Print Data from the Rear of Deque.
5. To Delete Data from the Front of Deque.
6. To Delete Data from the Rear of Deque.
7. To print the Deque.
2
Enter the data :

25
Data Added Successfully.


Type [N or n] to terminate the program.
Type [Y or y] to continue the program.

y
Please Choose one of the Operations::
1. To Insert Data at the Front of Deque.
2. To Insert Data at the Rear of Deque.
3. To Print Data from the Front of Deque.
4. To Print Data from the Rear of Deque.
5. To Delete Data from the Front of Deque.
6. To Delete Data from the Rear of Deque.
7. To print the Deque.
1
Enter the data :

45
Data Added Successfully.


Type [N or n] to terminate the program.
Type [Y or y] to continue the program.

y
Please Choose one of the Operations::
1. To Insert Data at the Front of Deque.
2. To Insert Data at the Rear of Deque.
3. To Print Data from the Front of Deque.
4. To Print Data from the Rear of Deque.
5. To Delete Data from the Front of Deque.
6. To Delete Data from the Rear of Deque.
7. To print the Deque.
2
Enter the data :

60
Data Added Successfully.


Type [N or n] to terminate the program.
Type [Y or y] to continue the program.

y
Please Choose one of the Operations::
1. To Insert Data at the Front of Deque.
2. To Insert Data at the Rear of Deque.
3. To Print Data from the Front of Deque.
4. To Print Data from the Rear of Deque.
5. To Delete Data from the Front of Deque.
6. To Delete Data from the Rear of Deque.
7. To print the Deque.
7
Data in Deque::
45 10 25 60 

Type [N or n] to terminate the program.
Type [Y or y] to continue the program.

y
Please Choose one of the Operations::
1. To Insert Data at the Front of Deque.
2. To Insert Data at the Rear of Deque.
3. To Print Data from the Front of Deque.
4. To Print Data from the Rear of Deque.
5. To Delete Data from the Front of Deque.
6. To Delete Data from the Rear of Deque.
7. To print the Deque.
3
Data at front:45


Type [N or n] to terminate the program.
Type [Y or y] to continue the program.

y
Please Choose one of the Operations::
1. To Insert Data at the Front of Deque.
2. To Insert Data at the Rear of Deque.
3. To Print Data from the Front of Deque.
4. To Print Data from the Rear of Deque.
5. To Delete Data from the Front of Deque.
6. To Delete Data from the Rear of Deque.
7. To print the Deque.
4
Data at rear:60


Type [N or n] to terminate the program.
Type [Y or y] to continue the program.

y
Please Choose one of the Operations::
1. To Insert Data at the Front of Deque.
2. To Insert Data at the Rear of Deque.
3. To Print Data from the Front of Deque.
4. To Print Data from the Rear of Deque.
5. To Delete Data from the Front of Deque.
6. To Delete Data from the Rear of Deque.
7. To print the Deque.
5
Data deleted from the front.

Type [N or n] to terminate the program.
Type [Y or y] to continue the program.

y
Please Choose one of the Operations::
1. To Insert Data at the Front of Deque.
2. To Insert Data at the Rear of Deque.
3. To Print Data from the Front of Deque.
4. To Print Data from the Rear of Deque.
5. To Delete Data from the Front of Deque.
6. To Delete Data from the Rear of Deque.
7. To print the Deque.
7
Data in Deque::
10 25 60 

Type [N or n] to terminate the program.
Type [Y or y] to continue the program.

y
Please Choose one of the Operations::
1. To Insert Data at the Front of Deque.
2. To Insert Data at the Rear of Deque.
3. To Print Data from the Front of Deque.
4. To Print Data from the Rear of Deque.
5. To Delete Data from the Front of Deque.
6. To Delete Data from the Rear of Deque.
7. To print the Deque.
6
Data deleted from the rear.

Type [N or n] to terminate the program.
Type [Y or y] to continue the program.

y
Please Choose one of the Operations::
1. To Insert Data at the Front of Deque.
2. To Insert Data at the Rear of Deque.
3. To Print Data from the Front of Deque.
4. To Print Data from the Rear of Deque.
5. To Delete Data from the Front of Deque.
6. To Delete Data from the Rear of Deque.
7. To print the Deque.
7
Data in Deque::
10 25

Type [N or n] to terminate the program.
Type [Y or y] to continue the program.

n

在上面的代码中,我们首先创建了一个双端队列数据结构,并使用各自的插入函数从队头和队尾向该双端队列中添加元素。

成功将数据插入双端队列后,下一步是对双端队列数据结构的两个端执行删除操作。有两个函数可以从双端队列的两端删除数据。

每次操作后,我们都使用 printDeque() 函数打印双端队列数据结构的内容,该函数从队头开始打印双端队列的所有内容,直到队尾。为了创建双端队列数据,我们使用了循环数组。

应用

工作窃取算法是一个双端队列如何使用的例子。[6]该技术用于调度多个 CPU 之间的任务。为每个处理器维护一个单独的双端队列,其中包含要执行的线程。处理器从双端队列中获取第一个元素来启动下一个线程(使用“移除第一个元素”的双端队列操作)。如果当前线程分叉,则当前线程被放回双端队列的队头(“在队头插入一个元素”),并启动一个新线程。

当其中一个处理器完成了其自身线程的执行(即其双端队列为空)时,它可以从另一个处理器“窃取”一个线程,方法是检索另一个处理器双端队列的最后一个元素(“移除最后一个元素”)并执行它。英特尔的 Threading Building Blocks (TBB) 包使用工作窃取机制进行并行编程。