隊列的順序存儲結構


隊列的順序存儲結構之循環隊列

隊列的定義: 只允許在一端進行操作,在另一端進行刪除操作的線性表。

隊列是一種先進先出的線性表,簡稱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 }
View Code

 

 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 }
View Code

 

 

完畢 - -

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM