Introduction
Dequeue refers to a two-way queue, which can insert and get data from the head of the queue, or insert and get data from the tail of the queue.
This article will introduce some basic operations on how to create dequeue and dequeue.
Implementation of two-way queue
Unlike ordinary queue items, two-way queues can be inserted and deleted at the head and tail respectively, so a dequeue needs to implement these 4 methods:
- insertFront(): Insert data from the head of the dequeue
- insertLast(): Insert data from the end of the dequeue
- deleteFront(): delete data from the dequeue header
- deleteLast(): Delete data from the end of the dequeue
Similarly, we also need a head and a rear to point to the head and tail nodes of the queue.
In other words, the queue that implements these four methods is a two-way queue. We don't care how it is implemented internally.
Next, let's intuitively feel the insert and delete operations of dequeue:
- Insert in the head
- Insert at the end
- Delete at the head
- Delete at the end
Two-way queues can also be implemented in many ways, such as circular arrays and linked lists.
Array implementation of two-way queue
Because the array itself has a context, that is to say, knowing that the head can get the data after it, and knowing that the rear can also get the data before it.
So in the implementation of the array, storing the index values of head and rear is enough.
We only need to add methods to insert data to the head and delete data to the tail:
//从头部入队列
public void insertFront(int data){
if(isFull()){
System.out.println("Queue is full");
}else{
//从头部插入ArrayDeque
head = (head + capacity - 1) % capacity;
array[head]= data;
//如果插入之前队列为空,将real指向head
if(rear == -1 ){
rear = head;
}
}
}
//从尾部取数据
public int deleteLast(){
int data;
if(isEmpty()){
System.out.println("Queue is empty");
return -1;
}else{
data= array[rear];
//如果只有一个元素,则重置head和real
if(head == rear){
head= -1;
rear = -1;
}else{
rear = (rear + capacity - 1)%capacity;
}
return data;
}
}
Dynamic array implementation of two-way queue
Dynamic arrays can dynamically change the size of the array, here we use multiplication to expand the array.
Look at how the extension method is implemented:
//因为是循环数组,这里不能做简单的数组拷贝
private void extendQueue(){
int newCapacity= capacity*2;
int[] newArray= new int[newCapacity];
//先全部拷贝
System.arraycopy(array,0,newArray,0,array.length);
//如果rear<head,表示已经进行循环了,需要将0-head之间的数据置空,并将数据拷贝到新数组的相应位置
if(rear < head){
for(int i=0; i< head; i++){
//重置0-head的数据
newArray[i]= -1;
//拷贝到新的位置
newArray[i+capacity]=array[i];
}
//重置rear的位置
rear = rear +capacity;
//重置capacity和array
capacity=newCapacity;
array=newArray;
}
}
Because it is a circular array, simple array copy cannot be done here. We need to judge the positions of rear and head to judge whether it has entered the circular structure.
If we enter the loop structure, we need to reset the corresponding field data and copy it to the new array.
The method of inserting data to the head and deleting data to the tail is the same as the implementation of the basic queue, and will not be listed here.
Linked list implementation of two-way queue
What is the problem if you use a linked list to implement a two-way queue?
Both inserting at the head and inserting at the tail can quickly locate the target node. But let's consider the issue of tail deletion.
To delete the tail, we need to find the previous node of the tail node and set this node to the rear node. This requires us to be able to find its previous node through the rear node.
So the basic linked list can no longer meet our needs. Here we need to use a doubly linked list.
public class LinkedListDeQueue {
//head节点
private Node headNode;
//rear节点
private Node rearNode;
class Node {
int data;
Node next;
Node prev;
//Node的构造函数
Node(int d) {
data = d;
}
}
public boolean isEmpty(){
return headNode==null;
}
//从队尾插入
public void insertLast(int data){
Node newNode= new Node(data);
//将rearNode的next指向新插入的节点
if(rearNode !=null){
rearNode.next=newNode;
newNode.prev=rearNode;
}
rearNode=newNode;
if(headNode == null){
headNode=newNode;
}
}
//从队首插入
public void insertFront(int data){
if(headNode == null){
headNode= new Node(data);
}else{
Node newNode= new Node(data);
newNode.next= headNode;
headNode.prev= newNode;
headNode= newNode;
}
}
//从队首删除
public int deleteFront(){
int data;
if(isEmpty()){
System.out.println("Queue is empty");
return -1;
}else{
data=headNode.data;
headNode=headNode.next;
headNode.prev=null;
}
return data;
}
//从队尾删除
public int deleteLast(){
int data;
if(isEmpty()){
System.out.println("Queue is empty");
return -1;
}else{
data=rearNode.data;
rearNode=rearNode.prev;
rearNode.next=null;
}
return data;
}
}
Each node in the doubly linked list has two pointers next and prev. Through these two pointers, we can quickly locate their next node and previous node.
Time complexity of doubly linked list
The above three implementations of enQueue and deQueue methods can basically be positioned immediately to enter the queue or exit the queue, so their time complexity is O(1).
The code address of this article:
This article has been included in http://www.flydean.com/13-algorithm-dequeue/
The most popular interpretation, the most profound dry goods, the most concise tutorial, and many tips you don't know are waiting for you to discover!
Welcome to pay attention to my official account: "Program those things", know technology, know you better!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。