隊列的順序存儲結構之循環隊列
隊列的定義: 只允許在一端進行操作,在另一端進行刪除操作的線性表。
隊列是一種先進先出的線性表,簡稱FIFO,允許插入的一端稱為隊尾,允許刪除的一端稱為隊頭。
1、隊列的順序存儲結構存在缺陷
原因:
假設一個隊列有n個元素,則順序存儲的隊列需要建立一個大於n的數組,並把隊列的所有元素存儲在數組的前n個單元,數組下標為0的一端即為對頭。
所謂的入隊,就是在隊尾追加一個元素,不需要移動任何元素,所以時間復雜度為O(1).
隊列的出隊是在對頭,即下標為0的位置,也就意味着,隊列中的所有位置都得向前移動,以保證下標為0的位置,即對頭不為空。此時時間復雜度為O(n)。
可是有時候想想,為什么出隊列時一定要全部移動呢?如果不限制隊列的元素一定要存儲在數組的前n個單元,出隊的性能就會大大增加。也就是說,隊頭不需要一定在下標為0的位置。
但如果不全部移動的話,又會引入新的問題?那就是數組的 “假溢出”
為了避免當只有一個元素時,對頭和隊尾重合使得處理變得麻煩,所以引入兩個指針,front指針指向對頭元素,rear指針指向隊尾元素的下一個元素。這樣當front等於rear時,不是隊列中有一個元素,而是表示空隊列。
假設數組的長度為5,空隊列及初始狀態如左圖所示,front與rear指針都指向下標為0的位置。當隊列中有4個元素時,front指針不變,rear指針指向下標為4的位置。
此時出隊兩個元素,則front指針指向下標為2的位置,rear不變。再入隊一個元素,front指針不變,此時rear指針移動到數組之外,這就產生了 “假溢出” 現象。
為了解決這種假溢出的現象。我們引入了循環隊列
2、循環隊列的定義
我們把隊列的頭尾相接的順序存儲結構稱之為循環隊列。
為了解決假溢出的現象,就是當隊列滿了,我們再從頭開始存數據,這是時候頭尾已經相連了,就形成了循環隊列。
繼續剛才的例子,將rear指針指向下標為0的位置,就不會導致rear指針指向不明的問題。
接着入隊兩個元素,會發現rear指針與front重合了
此時問題又來了,剛才說了,當rear等於front時,表示是空隊列,現在當隊列滿時,rear也等於front。那么如何判斷隊列到底是空的還是滿的了?
我們有兩個判斷方法:
辦法一是設置標志變量flag,當front = rear ,且flag =0 為隊列空,當front =rear ,且flag =1 時隊列滿。
辦法二是當隊列為空時,條件是front = rear ,當隊列滿時,我們修改其條件,保留一個元素的空間,也是就是說,當隊列滿時,數組里面還有一個空閑的單元。
例如下圖就表示了隊列已經滿了
就不能再插入元素了。
由於隊列是循環隊列,rear可能比front大,也可能比front小,所以假設隊列的最大尺寸為QueueSize, 隊列滿的判斷條件改為(rear + 1)%QueueSize = front. 隊列的長度為(rear - front + QueueSize)% QueueSize.
循環隊列的引入解決了數據移動的時間損耗,使得本來插入和刪除是O(n)的時間復雜度變成了O(1).
以上的部分文字和圖片Copy大佬:https://www.cnblogs.com/muzijie/p/5650187.html
循環隊列的順序存儲結構定義如下
typedef struct{ int data[MAXSIZE]; //容量
int front; //前驅下標
int real; //后繼下標
}SqQueue;
初始化隊列
1 /*初始化隊列*/
2 void InitQueue(SqQueue* Q){ 3 Q->front=0; 4 Q->real=0; //前驅和后繼都指向0
5 }
求一個循環隊列的長度
1 /*求一個循環隊列的長度*/
2 int QueueLength(SqQueue Q){ 3
4 return (Q.real-Q.front+MAXSIZE)%MAXSIZE; 5 }
循環隊列的入隊操作
1 /*入隊操作*/
2 int EnQueue(SqQueue* Q,int e){ 3 if(FullQueue(*Q)) 4 return 0; 5 Q->data[Q->rear]=e; 6 Q->rear = (Q->rear+1)%MAXSIZE; //將rear指針向后移一位
7 /*若到最后則轉到數組頭部*/
8 }
循環隊列的出隊操作
1 /*出隊操作*/
2 int DeQueue(SqQueue* Q){ 3 int e; 4 if(Q->front ==Q->rear){ 5 return 0; 6 } 7 e = Q->data[Q->front]; 8 Q->front = (Q->front+1)%MAXSIZE; 9 return e; 10 }
其它操作的實現代碼
1 #include <stdio.h>
2 #define MAXSIZE 20
3
4 typedef struct{ 5
6 int data[MAXSIZE]; //容量
7 int front; //前驅下標
8 int rear; //后繼下標
9
10 }SqQueue; 11
12 /*初始化隊列*/
13 void InitQueue(SqQueue* Q){ 14 Q->front=0; 15 Q->rear=0; //前驅和后繼都指向0
16 } 17
18 /*求一個循環隊列的長度*/
19 int QueueLength(SqQueue Q){ 20
21 return (Q.rear-Q.front+MAXSIZE)%MAXSIZE; 22 } 23
24 /*判斷是否隊滿*/
25 int FullQueue(SqQueue Q){ 26 if(QueueLength(Q) ==MAXSIZE) 27 return 1; 28 else
29 return 0; 30 } 31
32 /*入隊操作*/
33 int EnQueue(SqQueue* Q,int e){ 34 if(FullQueue(*Q)) 35 return 0; 36 Q->data[Q->rear]=e; 37 Q->rear = (Q->rear+1)%MAXSIZE; //將rear指針向后移一位
38 /*若到最后則轉到數組頭部*/
39 } 40
41 /*出隊操作*/
42 int DeQueue(SqQueue* Q){ 43 int e; 44 if(Q->front ==Q->rear){ 45 return 0; 46 } 47 e = Q->data[Q->front]; 48 Q->front = (Q->front+1)%MAXSIZE; 49 return e; 50 } 51
52 int main(){ 53
54 SqQueue s; 55 InitQueue(&s); 56 for(int i=0;i<10;i++){ 57 EnQueue(&s,i); 58 } 59
60 for( i=0;i<10;i++){ 61 printf("出隊元素:%d\n",DeQueue(&s)); 62 } 63
64 return 0; 65 }
附上Java代碼實現

1 package queue; 2 3 public class Queue { 4 5 int data[] = new int[20]; 6 int rear; // 后下標 7 int front; // 前下標 8 9 /** 10 * 初始化隊列 11 */ 12 public void initQueue(Queue Q) { 13 Q.front = 0; 14 Q.rear = 0; 15 } 16 17 /** 18 * 入隊操作 19 */ 20 public int enQueue(Queue Q, int e) { 21 if (fullQueue(Q) == 1) 22 return 0; 23 24 Q.data[Q.rear] = e; 25 Q.rear = (Q.rear + 1) % 20; 26 27 return e; 28 } 29 30 /** 31 * 出隊操作 32 */ 33 public int deQueue(Queue Q) { 34 int e; 35 if (queueLength(Q) == 0) 36 return 0; 37 38 e = Q.data[Q.front]; 39 Q.front = (Q.front + 1) % 20; 40 return e; 41 } 42 43 /** 44 * 判斷是否隊滿 45 */ 46 public int fullQueue(Queue Q) { 47 if ((Q.rear + 1) % 20 == Q.front) // 判斷是否為隊滿 48 return 1; 49 else 50 return 0; 51 } 52 53 /** 54 * 返回隊長度 55 */ 56 public int queueLength(Queue Q) { 57 58 return (Q.rear - Q.front + 20) % 20; 59 } 60 61 /** 62 * 判斷是否隊空 63 */ 64 public boolean elmptyQueue(Queue Q) { 65 if (Q.front == Q.rear) 66 return true; 67 return false; 68 } 69 }

1 package queue; 2 3 public class Test { 4 5 public static void main(String[] args) { 6 7 Queue queue = new Queue(); 8 System.out.println("初始化隊..."); 9 queue.initQueue(queue); 10 System.out.println("入隊操作..."); 11 for (int i = 0; i < 10; i++) 12 System.out.print(queue.enQueue(queue, i) + " "); 13 14 System.out.println(""); 15 System.out.println("判斷對是否為空..." + queue.elmptyQueue(queue)); 16 17 System.out.println("出隊操作..."); 18 for (int j = 0; j < 10; j++) 19 System.out.print(queue.deQueue(queue) + " "); 20 21 System.out.println(""); 22 System.out.println("判斷對是否為空..." + queue.elmptyQueue(queue)); 23 } 24 25 }
完畢 - -