鏈式棧:就是一種操作受限的單向鏈表,對單向鏈表還不了解的可先看一下之前的一篇關於單向鏈表的隨筆,鏈表(單向鏈表的建立、刪除、插入、打印),理解了單向鏈表后再來看鏈式棧就比較輕松了
鏈式棧的操作一般含有:出棧、入棧、棧的初始化、判斷棧是否為空、清空棧,下面先上聲明部分代碼
1 #include <stdio.h>
2 #include <stdlib.h>
3 #define Empty 0 /* 棧空 */
4 #define Avail 1 /* 棧可用 */
5
6 typedef struct SNode 7 { 8 int data; 9 struct SNode *next; 10 }StackNode; 11 typedef struct LStack 12 { 13 StackNode *top; /* 棧頂指針 */
14 StackNode *bottom; /* 棧底指針 */
15 int height; /* 鏈式棧高度 */
16 }LinkStack; 17
18 LinkStack InitStack (LinkStack pStack); /* 棧頂指針、棧底指針、棧高度初始化*/
19 LinkStack Push (LinkStack pStack); /* 入棧 */
20 LinkStack Pop (LinkStack pStack); /* 出棧 */
21 int StackEmpty (LinkStack pStack); /* 判斷棧是否為空 */
22 LinkStack DeletStack (LinkStack pStack);/* 清空棧 */
23 void DisplyStack (LinkStack pStack); /* 遍歷棧----自頂至底*/
一、節點的聲明
1 typedef struct SNode 2 { 3 int data; 4 struct SNode *next; 5 }StackNode;
鏈式棧節點的聲明與單向鏈表的聲明相同,都是由數據域和指針域組成,這里不再贅述
二、棧頂、棧底、棧高度的聲明
1 typedef struct LStack 2 { 3 StackNode *top; /* 棧頂指針 */
4 StackNode *bottom; /* 棧底指針 */
5 int height; /* 鏈式棧高度 */
6 }LinkStack;
三、函數聲明
1 LinkStack InitStack (LinkStack pStack); /* 棧頂指針、棧底指針、棧高度初始化*/
2 LinkStack Push (LinkStack pStack); /* 入棧 */
3 LinkStack Pop (LinkStack pStack); /* 出棧 */
4 int StackEmpty (LinkStack pStack); /* 判斷棧是否為空 */
5 LinkStack DeletStack (LinkStack pStack);/* 清空棧 */
6 void DisplyStack (LinkStack pStack); /* 遍歷棧----自頂至底*/
鏈式棧和單向鏈表的區別
上面已經提到的是鏈式棧是一種操作受限的單向鏈表(廢話··),先來回顧一下單向鏈表的建立過程(不清楚單向鏈表的可以先之前的另一篇隨筆鏈表(單向鏈表的建立、刪除、插入、打印)),單向鏈表在添加新的節點的時候是將原鏈表最后一個節點的
指針域指向新建的節點,然后新建節點指針域置為NULL作為鏈表的最后一個節點,而鏈式棧在添加新的節點的時候操作就不太一樣了,先來分析下棧的操作,棧只是棧頂來做插入和刪除操作,那么棧頂放在鏈表的頭部還是尾部呢?由於單向鏈表有頭指針
而棧頂指針也是必須的,那么就把棧頂指針當作頭指針來使用,比較好的辦法是把棧頂放到單鏈表的頭部。另外棧頂在頭部了,那么單鏈表的頭結點也就失去了意義,通常對於鏈式棧來說,是不需要頭結點的,現在來說鏈式棧添加新節點的操作
鏈式棧:新一個節點->將新建節點的指針域指向原棧頂節點->將棧頂指針移動到新建節點
單向鏈表:新建一個節點->將原鏈表最后的一個節點的指針域指向新建節點->新建節點的指針域置為NULL作為新鏈表的最后一個節點
為了方便讀者更加直觀了解這個過程下面上圖:
鏈式棧操作部分
一、入棧
1 /* Function: 入棧 */
2 LinkStack Push (LinkStack pStack) 3 { 4 int data; 5 StackNode *temp; 6
7 if ((temp = (StackNode *)malloc(sizeof(StackNode))) == NULL) 8 { 9 printf("內存空間不足\n"); 10 return pStack; 11 } 12 if (StackEmpty(pStack) == Empty) /* 如果棧為空 */
13 { 14 pStack.top = pStack.bottom = temp; /* 棧頂、棧底指針都指向新建節點 */
15 temp->next = NULL; /* 節點指針域為空 */
16 printf("Please input data"); 17 scanf("%d", &data); 18 pStack.top->data = data; 19 pStack.height++; 20
21 return pStack; 22 } 23 else /* 棧不為空 */
24 { 25 temp->next = pStack.top;/* 新建節點指向原來的棧頂 */
26 pStack.top = temp; /* 棧頂指針指向新建節點 */
27 printf("Please input data"); 28 scanf("%d", &data); 29 pStack.top->data = data; 30 pStack.height++; 31
32 return pStack; 33 } 34 }
二、出棧
1 /* Function: 出棧 */
2 LinkStack Pop (LinkStack pStack) 3 { 4 StackNode *Second; 5
6
7 if (StackEmpty(pStack) == Empty) /* 判斷棧是否為空 */
8 { 9 printf("棧為空,無法出棧\n"); 10 return pStack; 11 } 12 if (pStack.top == pStack.bottom) /* 如果出棧的元素為最后一個元素 */
13 { 14 printf("出棧元素為%d\n", pStack.top->data); 15 free(pStack.top); 16 pStack.top = pStack.bottom = NULL; /* 棧頂、棧底都指針都置為空 */
17 pStack.height--; 18
19 return pStack; 20 } 21 printf("出棧元素為%d\n", pStack.top->data); 22 Second = pStack.top->next; /* 指向棧頂的前一個元素*/
23
24 free(pStack.top); /* 釋放棧頂節點 */
25 pStack.top = Second;/* 將頭指針移動到新的棧頂節點 */
26 pStack.height--; 27
28 return pStack; 29 }
出棧時需要判斷三種情況,第一種情況:棧為空、第二種情況:棧中只有一個元素、第三種情況:棧中元素大於等於兩個
三、判斷棧是否為空
1 /* Function: 判斷棧是否為空 */
2 int StackEmpty (LinkStack pStack) 3 { 4 if (pStack.top == NULL && pStack.bottom == NULL) 5 { 6 return Empty; 7 } 8 else
9 { 10 return Avail; 11 } 12 }
四、遍歷棧
1 /* Function: 遍歷棧 自頂到底*/
2 void DisplyStack (LinkStack pStack) 3 { 4 if (StackEmpty(pStack) == Empty) 5 { 6 printf("棧為空,無法遍歷\n"); 7 return ; 8 } 9 printf("棧中元素["); 10 while (pStack.top != NULL) 11 { 12 printf("%d->", pStack.top->data); 13 pStack.top = pStack.top->next; 14 } 15 printf("]\n"); 16 }
五、清空棧
1 /* Function: 清空棧 */
2 LinkStack DeletStack (LinkStack pStack) 3 { 4 StackNode *del; 5
6 while (pStack.top != NULL) 7 { 8 del = pStack.top->next; /* 棧頂節點的前一個節點 */
9 free(pStack.top); /* 釋放節點 */
10 pStack.top = del; /* 棧頂指針移動到新棧頂 */
11 } 12
13 return pStack; 14 }
六、初始化棧頂、棧底指針和棧高度
1 /* Function: 初始化棧頂、棧底、棧高度*/
2 LinkStack InitStack (LinkStack pStack) 3 { 4 pStack.top = pStack.bottom = NULL; 5 pStack.height = 0; 6
7 return pStack; 8 }
鏈式棧實現完整代碼
1 #include <stdio.h>
2 #include <stdlib.h>
3 #define Empty 0 /* 棧空 */
4 #define Avail 1 /* 棧可用 */
5
6 typedef struct SNode 7 { 8 int data; 9 struct SNode *next; 10 }StackNode; 11 typedef struct LStack 12 { 13 StackNode *top; /* 棧頂指針 */
14 StackNode *bottom; /* 棧底指針 */
15 int height; /* 鏈式棧高度 */
16 }LinkStack; 17
18 LinkStack InitStack (LinkStack pStack); /* 棧頂指針、棧底指針、棧高度初始化*/
19 LinkStack Push (LinkStack pStack); /* 入棧 */
20 LinkStack Pop (LinkStack pStack); /* 出棧 */
21 int StackEmpty (LinkStack pStack); /* 判斷棧是否為空 */
22 LinkStack DeletStack (LinkStack pStack);/* 清空棧 */
23 void DisplyStack (LinkStack pStack); /* 遍歷棧----自頂至底*/
24
25 int main() 26 { 27 LinkStack p; 28 char ch; 29
30 p.height = 0; /* 棧高度初始化為零 */
31 p = InitStack (p); /* 棧初始化 */
32 printf("Do you want to push stack(Y/N)?"); 33 scanf(" %c", &ch); 34 while (ch == 'Y' || ch == 'y') 35 { 36 p = Push(p); /* 入棧 */
37 DisplyStack(p); /* 遍歷棧 */
38 printf("Do you want to push stack(Y/N)?"); 39 scanf(" %c", &ch); 40 } 41 printf("Do you want to pop stack(Y/N)?"); 42 scanf(" %c", &ch); 43 while (ch == 'Y' || ch == 'y') 44 { 45 p = Pop(p); /* 出棧 */
46 DisplyStack(p); /* 遍歷棧 */
47 printf("Do you want to pop stack(Y/N)?"); 48 scanf(" %c", &ch); 49 } 50
51 return 0; 52 } 53 /* Function: 初始化棧頂、棧底、棧高度*/
54 LinkStack InitStack (LinkStack pStack) 55 { 56 pStack.top = pStack.bottom = NULL; 57 pStack.height = 0; 58
59 return pStack; 60 } 61
62 /* Function: 判斷棧是否為空 */
63 int StackEmpty (LinkStack pStack) 64 { 65 if (pStack.top == NULL && pStack.bottom == NULL) 66 { 67 return Empty; 68 } 69 else
70 { 71 return Avail; 72 } 73 } 74
75 /* Function: 入棧 */
76 LinkStack Push (LinkStack pStack) 77 { 78 int data; 79 StackNode *temp; 80
81 if ((temp = (StackNode *)malloc(sizeof(StackNode))) == NULL) 82 { 83 printf("內存空間不足\n"); 84 return pStack; 85 } 86 if (StackEmpty(pStack) == Empty) /* 如果棧為空 */
87 { 88 pStack.top = pStack.bottom = temp; /* 棧頂、棧底指針都指向新建節點 */
89 temp->next = NULL; /* 節點指針域為空 */
90 printf("Please input data"); 91 scanf("%d", &data); 92 pStack.top->data = data; 93 pStack.height++; 94
95 return pStack; 96 } 97 else /* 棧不為空 */
98 { 99 temp->next = pStack.top;/* 新建節點指向原來的棧頂 */
100 pStack.top = temp; /* 棧頂指針指向新建節點 */
101 printf("Please input data"); 102 scanf("%d", &data); 103 pStack.top->data = data; 104 pStack.height++; 105
106 return pStack; 107 } 108 } 109
110 /* Function: 出棧 */
111 LinkStack Pop (LinkStack pStack) 112 { 113 StackNode *Second; 114
115
116 if (StackEmpty(pStack) == Empty) /* 判斷棧是否為空 */
117 { 118 printf("棧為空,無法出棧\n"); 119 return pStack; 120 } 121 if (pStack.top == pStack.bottom) /* 如果出棧的元素為最后一個元素 */
122 { 123 printf("出棧元素為%d\n", pStack.top->data); 124 free(pStack.top); 125 pStack.top = pStack.bottom = NULL; /* 棧頂、棧底都指針都置為空 */
126 pStack.height--; 127
128 return pStack; 129 } 130 printf("出棧元素為%d\n", pStack.top->data); 131 Second = pStack.top->next; /* 指向棧頂的前一個元素*/
132
133 free(pStack.top); /* 釋放棧頂節點 */
134 pStack.top = Second;/* 將頭指針移動到新的棧頂節點 */
135 pStack.height--; 136
137 return pStack; 138 } 139
140 /* Function: 遍歷棧 自頂到底*/
141 void DisplyStack (LinkStack pStack) 142 { 143 if (StackEmpty(pStack) == Empty) 144 { 145 printf("棧為空,無法遍歷\n"); 146 return ; 147 } 148 printf("棧中元素["); 149 while (pStack.top != NULL) 150 { 151 printf("%d->", pStack.top->data); 152 pStack.top = pStack.top->next; 153 } 154 printf("]\n"); 155 } 156
157 /* Function: 清空棧 */
158 LinkStack DeletStack (LinkStack pStack) 159 { 160 StackNode *del; 161
162 while (pStack.top != NULL) 163 { 164 del = pStack.top->next; /* 棧頂節點的前一個節點 */
165 free(pStack.top); /* 釋放節點 */
166 pStack.top = del; /* 棧頂指針移動到新棧頂 */
167 } 168
169 return pStack; 170 }