鏈式隊列----用鏈表實現,鏈式隊列就是一個操作受限的單向鏈表,如果讀者了解單向鏈表的建立過程,那理解鏈式隊列就很容易了,先回顧一下單向鏈表的建立過程
(不熟悉單向鏈表的可以先看看另一片隨筆,再回來看鏈式隊列理解起來更容易☺鏈表(單向鏈表的建立、刪除、插入、打印)
單向鏈表
單向鏈表節點的組成部分
1 struct link 2 { 3 int data; 4 struct link *next; 5 };
數據域:data----用來存儲節點數據
指針域:struct link *next----用來存儲下一個節點的地址
鏈式隊列和單向鏈表比就多了兩個指針,頭指針和尾指針(這里我多加了一個length來記錄隊列的長度)
1 typedef struct QNode /* 聲明鏈式隊列的結點 */
2 { 3 int data; 4 struct QNode *next; 5 }Node; 6 typedef struct QueuePoint /* 聲明鏈式隊列的首尾指針 */
7 { 8 Node *front; 9 Node *rear; 10 int length; /* 記錄鏈式隊列長度 */
11 }Queue;
后面就是單向鏈表的建立了,這里就不再贅述了,重點分析下頭指針的尾指針的移動,為了方便理解先附上main函數部分的代碼
1 main() 2 { 3 int i = 0; 4 char c; 5 Queue q; //鏈式隊列首尾指針 和 長度
6
7 q.front = q.rear = NULL; /* 首尾指針初始化 */
8 q.length = 0; /* 鏈式隊列長度初始化 */
9 q = init(q); /* 初始化隊列 */
10 printf("Do you want to append a new node(Y/N)?"); 11 scanf_s(" %c", &c); 12 while (c == 'Y' || c == 'y') 13 { 14 q = AppendNode(q); /* 入隊*/
15 DisplyNode(q); /* 按先進先出對隊列進行打印 */
16 printf("Do you want to append a new node(Y/N)?"); 17 scanf_s(" %c", &c); 18 } 19 printf("Do you want to delete node(Y/N)?"); 20 scanf_s(" %c", &c); 21 while (c == 'Y' || c == 'y') 22 { 23 q = DeletNode(q); 24 DisplyNode(q); 25 printf("Do you want to delete node(Y/N)?"); 26 scanf_s(" %c", &c); 27 } 28
29 return 0; 30 }
下面上圖
(靈魂畫手已上線)
簡單描述一下上圖的步驟
第一步:初始化隊列(就是添加一個頭節點在隊列中),頭結點不存儲數據,使隊首指針和隊尾指針都指向頭結點
第二步:入隊(添加節點),使隊尾指針指向頭新建的節點,隊首指針不變仍然指向頭結點
初始化隊列和入隊----實現代碼
1 //函數功能:初始化隊列(其實就是搞個頭結點放在隊列里面) 2 //單獨弄個子函數來初始化隊列是為了方便入隊的時候判斷隊列是否為空
3 Queue init (Queue p) 4 { 5 p.front = p.rear = (Node *)malloc(sizeof(Node)); 6 if (p.front == NULL && p.rear == NULL) 7 { 8 printf("initialization failed"); 9 exit(0); 10 } 11 p.front->next = NULL; 12
13 return p; 14 } 15 //函數功能:新建節點並添加到隊列中,記錄隊列長度
16 Queue AppendNode (Queue p) 17 { 18 int data; 19 Node *q; 20
21 q = (Node *)malloc(sizeof(Node)); 22 if (q == NULL) /* 判斷分配內存是否失敗 */
23 { 24 printf("No enough memory to allocate"); 25 exit(0); 26 } 27 p.rear->next = q; /* 最后一個節點的指針指向新建節點*/
28 p.rear = q; /* 隊尾指針指向新建節點*/
29
30 printf("Input node data\n"); 31 scanf("%d", &data); 32 p.rear->data = data; 33 p.rear->next = NULL; 34 p.length++; 35 return p; 36
37 }
后面來分析下出隊時首尾指針的變化,因為后面出隊時要用到判斷隊列是否為空的一個子函數,這里先附上子函數代碼
1 int IsemptyQueue(Queue p) 2 { 3 if (p.front == p.rear) /* 隊首指針和隊尾指針重合隊列為空 */
4 { 5 return Empty; 6 } 7 else
8 { 9 return NoEmpty; 10 } 11 }
出隊時隊首指針的位置是不變的,隊首指針始終指向頭節點,出隊時頭節點的指針域指向出隊節點的后一節點,並將出隊的節點用free()函數釋放掉,為了方便讀者理解下面上圖
出隊實現代碼
1 Queue DeletNode (Queue p) 2 { 3 Node *del; 4
5 if (IsemptyQueue(p) == Empty) /* 判斷隊列是否為空*/
6 { 7 printf("隊列為空,無法出隊 "); 8 return p; 9 } 10 else /* 隊列不為空 */
11 { 12 if (p.front->next == p.rear) /* 如果出隊的節點為最后一個節點 */
13 { 14 printf("出隊節點的數據為%d----", p.rear->data); 15 free(p.rear); /* 釋放最后一一個節點*/
16 p.rear = p.front; /* 隊首指針和隊尾指針都指向頭節點 */
17 p.front->next = NULL; 18 p.length--; 19 } 20 else
21 { 22 del = p.front->next; 23 printf("出隊節點的數據為%d----", del->data); 24 p.front->next = p.front->next->next; /* 使頭節點的指針域指向出隊節點的下一個節點 */
25 free(del); /* 釋放出隊的節點 */
26 p.length--; 27 } 28
29 return p; 30 } 31 }
順序隊列和鏈式隊列首尾指針的比較
1.順序隊列是用數組實現的,首指針在出隊的時候移動,尾指針在入隊的時候移動,需要考慮隊列為空和隊列為滿的兩種情況
2.鏈式隊列是用鏈表實現的,首指針不移動始終指向頭節點,尾指針在入隊的時候移動,只考慮隊列為空的情況(不用考慮滿是因為鏈表長度在程序運行過程中可以不斷增加,只要存儲空間夠malloc就能申請內存空間來存放節點)
下面附上完整代碼

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #define Empty 0 /* 隊列為空 */ 5 #define NoEmpty 1 /* 隊列不為空*/ 6 7 typedef struct QNode /* 聲明鏈式隊列的結點 */ 8 { 9 int data; 10 struct QNode *next; 11 }Node; 12 typedef struct QueuePoint /* 聲明鏈式隊列的首尾指針 */ 13 { 14 Node *front; 15 Node *rear; 16 int length; /* 記錄鏈式隊列長度 */ 17 }Queue; 18 19 void DisplyNode (Queue p); /* 打印隊列 */ 20 Queue init (Queue p); /* 初始化隊列 */ 21 Queue AppendNode (Queue p); /* 入隊 */ 22 Queue DeletNode (Queue p); /* 出隊 */ 23 int IsemptyQueue (Queue p); /* 判斷隊列是否為空*/ 24 main() 25 { 26 int i = 0; 27 char c; 28 Queue q; //鏈式隊列首尾指針 和 長度 29 30 q.front = q.rear = NULL; /* 首尾指針初始化 */ 31 q.length = 0; /* 鏈式隊列長度初始化 */ 32 q = init(q); /* 初始化隊列 */ 33 printf("Do you want to append a new node(Y/N)?"); 34 scanf_s(" %c", &c); 35 while (c == 'Y' || c == 'y') 36 { 37 q = AppendNode(q); /* 入隊 */ 38 DisplyNode(q); /* 按先進先出對隊列進行打印 */ 39 printf("Do you want to append a new node(Y/N)?"); 40 scanf_s(" %c", &c); 41 } 42 printf("Do you want to delete node(Y/N)?"); 43 scanf_s(" %c", &c); 44 while (c == 'Y' || c == 'y') 45 { 46 q = DeletNode(q); /* 出隊 */ 47 DisplyNode(q); /* 按先進先出對隊列進行打印 */ 48 printf("Do you want to delete node(Y/N)?"); 49 scanf_s(" %c", &c); 50 } 51 52 return 0; 53 } 54 int IsemptyQueue(Queue p) 55 { 56 if (p.front == p.rear) /* 隊首指針和隊尾指針重合隊列為空 */ 57 { 58 return Empty; 59 } 60 else 61 { 62 return NoEmpty; 63 } 64 } 65 Queue DeletNode (Queue p) 66 { 67 Node *del; 68 69 if (IsemptyQueue(p) == Empty) /* 判斷隊列是否為空*/ 70 { 71 printf("隊列為空,無法出隊 "); 72 return p; 73 } 74 else /* 隊列不為空 */ 75 { 76 if (p.front->next == p.rear) /* 如果出隊的節點為最后一個節點 */ 77 { 78 printf("出隊節點的數據為%d----", p.rear->data); 79 free(p.rear); /* 釋放最后一一個節點*/ 80 p.rear = p.front; /* 隊首指針和隊尾指針都指向頭節點 */ 81 p.front->next = NULL; 82 p.length--; 83 } 84 else 85 { 86 del = p.front->next; 87 printf("出隊節點的數據為%d----", del->data); 88 p.front->next = p.front->next->next; /* 使頭節點的指針域指向出隊節點的下一個節點 */ 89 free(del); /* 釋放出隊的節點 */ 90 p.length--; 91 } 92 93 return p; 94 } 95 } 96 //函數功能:初始化隊列(其實就是搞個頭結點放在隊列里面) 97 //單獨弄個子函數來初始化隊列是為了方便入隊的時候判斷隊列是否為空 98 Queue init (Queue p) 99 { 100 p.front = p.rear = (Node *)malloc(sizeof(Node)); 101 if (p.front == NULL && p.rear == NULL) 102 { 103 printf("initialization failed"); 104 exit(0); 105 } 106 p.front->next = NULL; 107 108 return p; 109 } 110 //函數功能:新建節點並添加到隊列中,記錄隊列長度 111 Queue AppendNode (Queue p) 112 { 113 int data; 114 Node *q; 115 116 q = (Node *)malloc(sizeof(Node)); 117 if (q == NULL) /* 判斷分配內存是否失敗 */ 118 { 119 printf("No enough memory to allocate"); 120 exit(0); 121 } 122 p.rear->next = q; /* 最后一個節點的指針指向新建節點*/ 123 p.rear = q; /* 隊尾指針指向新建節點*/ 124 125 printf("Input node data\n"); 126 scanf("%d", &data); 127 p.rear->data = data; 128 p.rear->next = NULL; 129 p.length++; 130 return p; 131 132 } 133 //函數功能:按照先進先出原則對隊列進行打印 134 void DisplyNode (Queue p) 135 { 136 if (IsemptyQueue(p) == Empty) 137 { 138 printf("隊列為空,無法打印\n"); 139 } 140 else 141 { 142 p.front = p.front->next; 143 printf("當前隊列中的%d個節點[", p.length); 144 while (p.front != NULL) 145 { 146 printf("%d->", p.front->data); 147 p.front = p.front->next; 148 } 149 putchar(']'); 150 putchar('\n'); 151 } 152 }
程序試運行結果:
思考:上面說出隊的時候鏈式隊列的頭指針是不移動的,始終指向頭節點,其實也可以像順序隊列那樣頭指針在出隊的時候也相應的移動,也能正常完成入隊、出隊、先進先出打印的操作
下面附上鏈式隊列鏈接:隊列(鏈式隊列)----C語言