隊列及其實現


 

 

  和棧相反,隊列是一種先進先出的特殊線性表,它只允許在表的一段進行插入,而在另一端刪除元素,這里需要注意,隊列不允許在中間部位進行操作,隊列通常有兩種實現方式:順序結構實現、鏈式結構實現。

隊列有下面幾個操作:

  • InitQueue()   ——初始化隊列
  • EnQueue()        ——進隊列
  • DeQueue()        ——出隊列
  • IsQueueEmpty()——判斷隊列是否為空
  • IsQueueFull()    ——判斷隊列是否已滿

  順序結構實現如下:

 

 

  對於順序隊列,入隊的新元素是在線性表的最后,時間復雜度O(1),出隊時需要將后續的所有元素向前移動,時間復雜度時O(n),那么如何使它的時間復雜度降低到O(1)呢?

  定義front使其始終代表頭的下標

出隊時將對頭元素返回,且front++

  定義rear使其始終代表隊尾下一個元素的下標

入隊時將新元素插入,且rear++

  順序隊列的關鍵狀態

初始狀態:length == 0 , front == 0 , rear == 0;

空隊列狀態:length == 0 , front == rear;

滿隊列狀態:length == capacity , front == rear;

  循環使用隊列中的空間

入列:rear = (rear + 1)%capacity;

出列:front = (front + 1)%capacity;

小結:優化的順序隊列利用順序空間提高出列操作的效率。

 

  鏈式結構如下:

 

對於鏈式隊列,入隊的新元素是在線性表的最后,時間復雜度O(n),出隊時需要將后續的所有元素向前移動,時間復雜度時O(1),那么如何使它的時間復雜度降低到O(1)呢?

  定義rear指針始終向鏈表中的最后一個元素

入隊時將新元素通過rear插入隊尾,且將rear指向新元素

  鏈式隊列的關鍵狀態

空隊列狀態:front == NULL , rear == NULL;

  關鍵操作

入隊:

 rear -> next = node;

 rear =  node;

 node -> next = NULL;

出列:

 front = front -> next;

小結:優化的鏈式隊列定義rear指針向隊尾元素提高出列操作的效率。

  但是這樣的話,空間利用率不高,所以最后再介紹一種隊列:循環隊列。為充分利用向量空間,克服"假溢出"現象的方法是:將向量空間想象為一個首尾相接的圓環,如下圖:

  

  這里需要注意的是,循環隊列中,由於入隊時尾指針向前追趕頭指針;出隊時頭指針向前追趕尾指針,造成隊空和隊滿時頭尾指針均相等。因此,無法通過條件front==rear來判別隊列是"空"還是"滿"。在C語言中不能夠用動態分配的一位數組來實現循環隊列,如果用戶的應用程序中設有循環隊列的話,則必須為它設定一個最長隊列長度;若用戶無法預估所用隊里的最大長度,則應該采用鏈式隊列。具體實現代碼如下:

 1 #include<stdio.h>
 2 
 3 #include<stdlib.h>
 4 
 5 #define MAXSIZE 50                                    //隊列是最大長度
 6 
 7 typedef struct                                        //點實體結構
 8 {  9 
 10     char name[10];  11 
 12     char id[8];  13 
 14     float x,y,z;  15 
 16 }Point;  17 
 18 typedef struct                                        //循環列表結構
 19 {  20 
 21     Point *base;  22 
 23     int front;  24 
 25     int rear;  26 
 27 }SqQueue;  28 
 29 int initQueue(SqQueue *Q);  30 
 31 int isEmpty(SqQueue *Q);  32 
 33 int isFull(SqQueue *Q);  34 
 35 int enQueue(SqQueue *Q,Point e);  36 
 37 int deQueue(SqQueue *Q,Point *e);  38 
 39 int main(void)  40 {  41 
 42     char choice;  43 
 44  Point temp;  45 
 46     SqQueue *Q = (SqQueue *)malloc(sizeof(SqQueue));    //聲明隊列
 47 
 48     initQueue(Q);                                        //構造隊列
 49 
 50     printf("請選擇操作:\n"
 51 
 52         "a:入隊 b:出隊 q:退出\n");  53 
 54     while(scanf("%c", &choice) == 1)  55  {  56         //元素入隊
 57 
 58         if(choice == 'a')  59  {  60 
 61             printf("請輸入點名:\n");  62 
 63             scanf("%s", &temp.name);  64 
 65             printf("請輸入點號:\n");  66 
 67             scanf("%s", &temp.id);  68 
 69             printf("請輸入x坐標:\n");  70 
 71             scanf("%f", &temp.x);  72 
 73             printf("請輸入y坐標:\n");  74 
 75             scanf("%f", &temp.y);  76 
 77             printf("請輸入z坐標:\n");  78 
 79             scanf("%f", &temp.z);  80 
 81             enQueue(Q, temp);                                //插入元素到隊尾
 82 
 83             fflush(stdin);                                    //清空輸入緩存
 84 
 85             printf("請選擇操作:\n"        
 86 
 87                 "a:入隊 b:出隊 q:退出\n");  88  }  89 
 90         //元素出隊
 91         else if(choice == 'b')  92  {  93             //刪除失敗的情況
 94 
 95             if(deQueue(Q, &temp) == -1)  96 
 97  {  98 
 99                 fflush(stdin);                                    //清空輸入緩存
100 
101                 printf("請選擇操作:\n"
102 
103                     "a:入隊 b:出隊 q:退出\n"); 104 
105                 continue; 106 
107  } 108 
109             printf("刪除的節點的信息為:\n"
110 
111                 "點名:%s\n"
112 
113                 "點號:%s\n"
114 
115                 "x坐標:%.2f\n"
116 
117                 "y坐標:%.2f\n"
118 
119                 "z坐標:%.2f\n", 120 
121  temp.name, temp.id, temp.x, temp.y, temp.z); 122 
123             fflush(stdin);                                    //清空輸入緩存
124 
125             printf("請選擇操作:\n"
126 
127                 "a:入隊 b:出隊 q:退出\n"); 128 
129  } 130 
131         //退出
132 
133         else if(choice == 'q') 134 
135             break; 136 
137         //輸入錯誤
138 
139         else
140 
141  { 142 
143             fflush(stdin);                                    //清空輸入緩存
144 
145             printf("輸入錯誤,輸入應該為‘a’或‘b’或‘q’!\n"
146 
147                 "請選擇操作:\n"
148 
149                 "a:入隊 b:出隊 q:退出\n"); 150 
151  } 152 
153  } 154 
155     free(Q->base); 156 
157  free(Q); 158 
159     printf("Done!\n"); 160 
161     return 0; 162 
163 } 164 
165 //構造一個空隊列
166 
167 int initQueue(SqQueue *Q) 168 
169 { 170 
171     Q->base=(Point *)malloc(MAXSIZE * sizeof(Point)); 172 
173     if(!Q->base) 174 
175  { 176 
177         printf("分配空間錯誤,初始化失敗!\n"); 178 
179         return -1; 180 
181  } 182 
183     Q->front = Q->rear = 0; 184 
185     printf("隊列初始化成功!\n"); 186 
187     return 0; 188 
189 } 190 
191 //判斷隊列是否為空
192 
193 int isEmpty(SqQueue *Q) 194 
195 { 196 
197     if(Q->front == Q->rear) 198 
199         return 1; 200 
201     else 
202 
203         return 0; 204 
205 } 206 
207 //判斷隊列是否為滿
208 
209 int isFull(SqQueue *Q) 210 
211 { 212 
213     if(Q->front == (Q->rear + 1) % MAXSIZE) 214 
215         return 1; 216 
217     else 
218 
219         return 0; 220 
221 } 222 
223 //插入元素e為Q的新隊尾元素
224 
225 int enQueue(SqQueue *Q,Point e) 226 { 227 
228     if(isFull(Q)) 229 
230  { 231 
232         printf("隊列已滿,插入失敗!\n"); 233 
234         return -1; 235 
236  } 237 
238 
239 
240     Q->base[Q->rear] = e; 241 
242     Q->rear = (Q->rear + 1) % MAXSIZE; 243 
244     printf("插入成功!\n"); 245 
246     return 0 ; 247 
248 } 249 
250 //刪除Q的隊頭元素,用e返回其值
251 
252 int deQueue(SqQueue *Q,Point *e) 253 
254 { 255 
256     if(isEmpty(Q)) 257 
258  { 259 
260         printf("隊列為空,刪除失敗!\n"); 261 
262         return -1; 263 
264  } 265     *e = Q->base[Q->front]; 266 
267     Q->front = (Q->front + 1) % MAXSIZE; 268 
269     printf("刪除成功!\n"); 270 
271     return 0; 272 
273 }       
XHqueue

我用Dev-C++的環境編譯之后的結果如下,這里我任意輸入了幾個例子,以供大家體會:

 


免責聲明!

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



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