Queue Introduction - 队列简介
Made by Mike_Zhang
数据结构与算法主题:
1 Introduction to Queue
Queue (队列) is another fundamental data structure, which is similar to the Stack
A queue is a collection of objects that are inserted and removed according to the first-in, first-out (FIFO) principle, while Stack is LIFO.
[Example]
Like the queue in the real life:
the first person got in the queue will first get the ticket and leave the queue, while the last person in the queue will be the last one get the ticket.
Image: Goodrich, M., Tamassia, R., & O’reilly, A. (2014). Data Structures and Algorithms in Java, 6th Edition. John Wiley & Sons.
2 Queue Abstract Data Type
See what is the Abstract Data Type
enqueue(e)
: Add an element e
to the back of the queue;dequeue()
: Remove and return the first element of the queue, or null
if the queue is empty;
first()
: Return but NOT remove the first element of the queue, or null
if the queue is empty;size()
: Return the number of elements in the queue;isEmpty()
: Return a boolean value indicating whether the queue is empty.
Define the Queue interface:
1 |
|
3 java.util.Queue Interface
Queue ADT | java.util.Queue throws exceptions |
java.util.Queue returns special value |
---|---|---|
enqueue(E e) |
add(E e) |
offer(E e) |
dequeue() |
remove(E e) |
poll() |
first() |
element() |
peek() |
size() |
size() |
size() |
isEmpty() |
isEmpty() |
isEmpty() |
4 Queue ADT Implementations
4.1 Implement Queue Using Array
- Using an array
data
to store the elements in the stack, with fixed size of the array, $N$. - Using the array circularly by indicating 2 variables:
f
: indicate the index of the first element of Queue in the array,(f + 1) % data.length;
indicates the new front of the Queue in the array when callingdequeue()
;size
: indicate the number of elements in the Queue, using(f + sz) % data.length
to indicate the index of the tail of the Queue in the array when callingenqueue(E e)
.
Java implementation:
1 |
|
Test:
1 |
|
Result:
1 |
|
Advantages of using an array to implement the Queue:
Simple and efficient;
Each method just includes some primitive operations, which is easy to understand and implement.
Running time of each method:
Method | Running time |
---|---|
size() |
$O(1)$ |
isEmpty() |
$O(1)$ |
enqueue(e) |
$O(1)$ |
dequeue() |
$O(1)$ |
first() |
$O(1)$ |
- Therefore, using Array to implement the Queue is efficient, for each method runs in constant time, $O(1)$ time.
Drawbacks of using an array to implement the Queue:
- It is based on a fixed size of the array, $N$, which means the size of the Queue is fixed, limited and unchangeable, while the the actual size of the Queue is dynamic.
- If we needs much less space than the reserved size, memory is wasted.
- If we try to enqueue an element into the Queue when the array storage is full, the program will throw an exception, and we cannot enqueue any more elements into the Queue.
To solve the above problem, we can use a LinkedList to implement the Queue.
4.2 Implement Queue Using LinkedList
- Using a singly linked list to store the elements in the queue;
- The memory usage is always associated with the actual number of elements in the Queue, without a capacity limitation;
- According to the queue ADT, we can adapt our SinglyLinkedList class to define a new LinkedQueue class:
Methods in Queue | Method in SingleLinkedList |
---|---|
size() |
getSize() |
isEmpty() |
isEmpty() |
enqueue(e) |
addAtTail(e) |
dequeue() |
deleteAtHead() |
first() |
getHead() |
Java implementation:
(Import the SingleLinkedList
class from the post-Linked List Introduction - 链表简介)
1 |
|
Test:1
2
3
4
5
6
7
8
9
10
11
12
13
14public static void main(String[] arg) {
Queue<Integer> queue = new LinkedQueue<>();
System.out.println(queue.isEmpty()); // true
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
System.out.println(queue.size()); // 3
System.out.println(queue.toString()); // 1 2 3
System.out.println(queue.first()); // 1
System.out.println(queue.dequeue()); // 1
System.out.println(queue.first()); // 2
queue.enqueue(4);
System.out.println(queue.toString()); // 2 3 4
}
Result:
1 |
|
5 Circular Queue
We have discussed Circularly Linked List in the post - Linked List Introduction - 链表简介.
Similarly, there is CircularQueue
interface extends from Queue
with a useful rotate()
method:
1 |
|
CircularQueue
can be implemented by using CircularlyLinkedList
to generate the LinkedCircularQueue
:
(Import the CircularlyLinkedList
class from the post-Linked List Introduction - 链表简介)
1 |
|
5.1 Circular Queue Application - Josephus Problem
I have studied and discussed Josephus Problem in the post - Python对约瑟夫问题(Josephus Problem)的高效解决方法 with Python implementation.
Now, it is also easy and efficient to solve this problem with Circular Queue because the basic of Josephus Problem is rotate and dequeue, which can be easily implemented by Circular Queue.
1 |
|
Test:
1 |
|
Result:
1 |
|
The result is correct and can be verified by the UltraFish Plus - Python对约瑟夫问题的高效解决方法 Josephus Problem with Python
References
Goodrich, M., Tamassia, R., & O’reilly, A. (2014). Data Structures and Algorithms in Java, 6th Edition. John Wiley & Sons.
写在最后
Queue 相关的知识会继续学习,继续更新.
最后,希望大家一起交流,分享,指出问题,谢谢!
原创文章,转载请标明出处
Made by Mike_Zhang