和棧相反,隊列是一種先進先出的特殊線性表,它只允許在表的一段進行插入,而在另一端刪除元素,這里需要注意,隊列不允許在中間部位進行操作,隊列通常有兩種實現方式:順序結構實現、鏈式結構實現。
隊列有下面幾個操作:
- 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 }
我用Dev-C++的環境編譯之后的結果如下,這里我任意輸入了幾個例子,以供大家體會: