目錄
1、什么是隊列
2、隊列的實現
2.1、基于簡單循環數組的實現
2.1.1、為什么需要循環數組
2.1.2、代碼實現
2.1.3、性能和局限性
2.2、基于動態循環數組的實現
2.2.1、代碼實現
2.2.2、性能
2.3、基于鏈表的實現方法
2.3.1、代碼實現
2.3.2、性能
正文
1、什么是隊列
- 定義:隊列是一種只能在一端插入(隊尾),在另一端刪除(隊首)的有序線性表。
-
在隊列中插入一個元素,稱為入隊(EnQueue)。從隊列中刪除一個元素,稱為出隊(DeQueue)。試圖對一個空隊列執行出隊操作稱為下溢(underflow),試圖對一個滿隊列執行入隊操作稱為溢出(overflow)。
圖1-1 隊列
2、隊列的實現
- 基于簡單循環數組的實現
- 基于動態循環數組的實現
- 基于鏈表的實現方法
2.1、基于簡單循環數組的實現
2.1.1、為什么需要循環數組
-
首先,分析是否可以借鑒基于簡單數組實現棧的方法來實現隊列。由隊列的定義可知,只能在一端執行插入操作,而在另一端執行刪除操作。當執行多次操作之后,出現如下問題,數組中靠前的空間浪費。
圖2-1 簡單數組實現隊列 -
為了解決這個問題,假設數組是循環存儲的方式,即將數組最后一個元素和第一個元素看作是連續的。依據這個假設,如果數組前端有空閑的空間,指向隊尾的指針就能夠很容易地移動到下一個空閑的位置。
圖2-2 簡單循環數組實現隊列 - 在數組中,采用循環增加元素的方式,并使用兩個變量分別記錄隊首元素和隊尾元素。由于是固定大小的數組,可能會出現數組被填滿的情況。這是如果執行入隊操作,將拋出“隊列滿異常”。
2.1.2、代碼實現
public class ArrayQueue {
private int front;
private int rear;
private int capacity;
private int[] array;
//初始化
private ArrayQueue(int size){
capacity=size;
front=-1;
rear=-1;
array=new int[size];
}
//創隊列
public static ArrayQueue createQueue(int size){
return new ArrayQueue(size);
}
//是否空隊列
public boolean isEmpty(){
return (front==-1);
}
//是否滿隊列
public boolean isFull(){
return ((rear+1)%capacity==front);
}
//隊列大小
public int getQueueSize(){
return ((capacity-front+rear+1)%capacity);
}
//出隊
public int deQueue(){
int data=-1;
if(isEmpty()){
return data;
}else {
data=array[front];
if(front==rear){
//空隊列
front=rear=-1;
}else {
front=(front+1)%capacity;
}
}
return data;
}
//入隊
public void enQueue(int data){
if(isFull()){
return;
}
else {
rear=(rear+1)%capacity;
array[rear]=data;
if(front==-1){
front=rear;
}
}
}
}
2.1.3、性能和局限性
-
性能:
圖2-3 基于簡單循環數組實現性能 - 局限性:用于實現隊列的數組的最大空間必須預先聲明且不能改變。試圖對一個滿隊列執行入隊操作會產生異常。
2.2、基于動態循環數組的實現
- 與簡單循環數組的區別在于,試圖對一個滿隊列執行入隊操作時,會動態增加數組的大小,使之可以成功入隊元素。
2.2.1、代碼實現
public class DynArrayQueue {
private int front;
private int rear;
private int capacity;
private int[] array;
//構造函數
private DynArrayQueue(){
capacity=1;
front=-1;
rear=-1;
array=new int[1];
}
//創隊列
public static DynArrayQueue createDynArrayQueue(){
return new DynArrayQueue();
}
//是否空隊列
public boolean isEmpty(){
return (front==-1);
}
//是否滿隊列
public boolean isFull(){
return ((rear+1)%capacity==front);
}
//隊列大小
public int getQueueSize(){
if(front==-1){
return 0;
}
int size=(capacity-front+rear+1)%capacity;
if(size==0){
return capacity;
}else {
return size;
}
}
//重置數組
public void resizeQueue(){
int initCapacity=capacity;
capacity*=2;
int[] oldArray=array;
array=new int[this.capacity];
for(int i=0;i<oldArray.length;i++){
array[i]=oldArray[i];
}
if(rear<front){
for(int i=0;i<front;i++){
array[i+initCapacity]=this.array[i];
array[i]=-1;
}
rear=rear+initCapacity;
}
}
//入隊
public void enQueue(int data){
if(isFull()){
resizeQueue();
}
rear=(rear+1)%capacity;
array[rear]=data;
if(front==-1){
front=rear;
}
}
//出隊
public int deQueue(){
int data=-1;
if(this.isEmpty()){
return data;
}else {
data=array[front];
if(front==rear){
//空隊列
front=rear=-1;
}else {
front=(front+1)%capacity;
}
}
return data;
}
}
2.2.2、性能
圖2-4 基于動態循環數組實現性能
2.3、基于鏈表的實現方法
-
通過在鏈表的末端插入元素的方法實現入隊操作,通過刪除鏈表表頭元素的方法實現出隊操作。
圖2-5 鏈表實現隊列
2.3.1、代碼實現
public class LLQueue {
private ListNode frontNode;
private ListNode rearNode;
//構造函數
private LLQueue(){
this.frontNode=null;
this.rearNode=null;
}
//創隊列
public static LLQueue creteQueue(){
return new LLQueue();
}
//是否空隊列
public boolean isEmpty(){
return (frontNode==null);
}
//入隊
public void enQueue(int data){
ListNode newNode=new ListNode(data);
if(rearNode!=null){
rearNode.setNext(newNode);
}
rearNode=newNode;
if(frontNode==null){
frontNode=rearNode;
}
}
//出隊
public int deQueue(){
int data=-1;
if(isEmpty()){
return data;
}else {
data=frontNode.getData();
frontNode=frontNode.getNext();
}
return data;
}
}
2.3.2、性能
圖2-6 基于鏈表實現性能