1栈 Stack ADT
2一、前提条件:栈是一种线性表。
3
4它的特点是:只能在一端插入和删除。
5
6这一端叫:栈顶 top
7
8另一端叫:栈底 bottom
9
10二、核心概念
11
12栈的规则是:后进先出 LIFO
13
14也就是:Last In First Out
15
16例如依次入栈:
171
182
193
20
21栈内逻辑是:
22栈顶
23 ↓
243
252
261
27
28先进的扔到栈底,后进的在栈顶
29
30出栈顺序是:
313 -> 2 -> 1
32
33三、基本操作
34
35栈 ADT 常见操作:
36
37InitStack 初始化栈
38Push 入栈
39Pop 出栈
40GetTop 取栈顶元素
41IsEmpty 判空
42IsFull 判满
43
44四、顺序栈
451. 存储结构:用数组实现。
46
47#define MAXSIZE 100
48
49struct Stack {
50 int data[MAXSIZE];
51 int top;
52};
53
54这里:
55data 存元素
56top 表示栈顶下标
57
582. top 的定义
59
60常见写法:top = -1 表示空栈
61
62如果压入第一个元素:
63
64top = 0
65
66栈:
67
68data[0]
69
70如果再压入一个:
71
72top = 1
73
74栈:
75
76data[0], data[1]
77
78所以:top 永远指向当前栈顶元素。
79
80五、顺序栈 C 语言模板
81
821. 初始化
83void InitStack(struct Stack* s)
84{
85 s->top = -1;
86}
87
882. 判空
89int IsEmpty(struct Stack* s)
90{
91 return s->top == -1;
92}
93
943. 判满
95int IsFull(struct Stack* s)
96{
97 return s->top == MAXSIZE - 1;
98}
99
1004. 入栈 Push
101int Push(struct Stack* s, int x)
102{
103 if (IsFull(s)) {
104 return 0;
105 }
106
107 s->top++;
108 s->data[s->top] = x;
109
110 return 1;
111}
112
113也可以写成:
114s->data[++s->top] = x;
115
116
1175. 出栈 Pop
118int Pop(struct Stack* s, int* x)
119{
120 if (IsEmpty(s)) {
121 return 0;
122 }
123
124 *x = s->data[s->top];
125 s->top--;
126
127 return 1;
128}
129
130这里用:int* x
131
132是为了把出栈元素带回去。
133
1346. 读取栈顶 GetTop
135int GetTop(struct Stack* s, int* x)
136{
137 if (IsEmpty(s)) {
138 return 0;
139 }
140
141 *x = s->data[s->top];
142
143 return 1;
144}
145
146注意:
147
148GetTop 只读取,不删除。
149Pop 读取并删除。
150
151六、顺序栈完整代码
152#define MAXSIZE 100
153
154struct Stack {
155 int data[MAXSIZE];
156 int top;
157};
158
159void InitStack(struct Stack* s)
160{
161 s->top = -1;
162}
163
164int IsEmpty(struct Stack* s)
165{
166 return s->top == -1;
167}
168
169int IsFull(struct Stack* s)
170{
171 return s->top == MAXSIZE - 1;
172}
173
174int Push(struct Stack* s, int x)
175{
176 if (IsFull(s)) {
177 return 0;
178 }
179
180 s->top++;
181 s->data[s->top] = x;
182
183 return 1;
184}
185
186int Pop(struct Stack* s, int* x)
187{
188 if (IsEmpty(s)) {
189 return 0;
190 }
191
192 *x = s->data[s->top];
193 s->top--;
194
195 return 1;
196}
197
198int GetTop(struct Stack* s, int* x)
199{
200 if (IsEmpty(s)) {
201 return 0;
202 }
203
204 *x = s->data[s->top];
205
206 return 1;
207}
208七、顺序栈例子
209
210初始:top = -1
211栈为空
212
213执行:Push(&s, 10);
214
215变成:
216data[0] = 10
217top = 0
218
219执行:Push(&s, 20);
220
221变成:
222
223data[0] = 10
224data[1] = 20
225top = 1
226
227栈顶是:20
228
229执行:Pop(&s, &x);
230
231得到:
232
233x = 20
234top = 0
235
236栈里剩:10
237
238八、链式栈
239
240顺序栈用数组,有最大容量限制。
241
242链式栈用链表,没有固定容量限制。
243
2441. 存储结构
245
246struct Node {
247 int data;
248 struct Node* next;
249};
250
251struct LinkedStack {
252 struct Node* top;
253};
254
255这里:top 指向链表第一个节点。
256
257也就是:链表头部就是栈顶。
258
259九、链式栈 C 语言模板
2601. 初始化
261void InitLinkedStack(struct LinkedStack* s)
262{
263 s->top = NULL;
264}
2652. 判空
266int IsLinkedStackEmpty(struct LinkedStack* s)
267{
268 return s->top == NULL;
269}
2703. 入栈 Push
271
272链式栈入栈本质是:
273
274头插法
275#include <stdlib.h>
276
277int PushLinkedStack(struct LinkedStack* s, int x)
278{
279 struct Node* node =
280 malloc(sizeof(struct Node));
281
282 if (node == NULL) {
283 return 0;
284 }
285
286 node->data = x;
287 node->next = s->top;
288 s->top = node;
289//这里相当于是把node的next赋NULL,之后把top指向node,每次头插进之后,top都指向新的node,
290 return 1;
291}
292
2934. 出栈 Pop
294
295链式栈出栈本质是:
296
297删除头节点
298int PopLinkedStack(struct LinkedStack* s, int* x)
299{
300 if (IsLinkedStackEmpty(s)) {
301 return 0;
302 }
303
304 struct Node* p = s->top;
305
306 *x = p->data;
307
308 s->top = p->next;
309//相当于就是把top对应的值返回给x,然后top去取next的值,这样相当于把原节点跳过
310 free(p);
311
312 return 1;
313}
314
3155. 读取栈顶
316int GetLinkedStackTop(struct LinkedStack* s, int* x)
317{
318 if (IsLinkedStackEmpty(s)) {
319 return 0;
320 }
321
322 *x = s->top->data;
323
324 return 1;
325}
326
327十、链式栈完整代码
328#include <stdlib.h>
329
330struct Node {
331 int data;
332 struct Node* next;
333};
334
335struct LinkedStack {
336 struct Node* top;
337};
338
339void InitLinkedStack(struct LinkedStack* s)
340{
341 s->top = NULL;
342}
343
344int IsLinkedStackEmpty(struct LinkedStack* s)
345{
346 return s->top == NULL;
347}
348
349int PushLinkedStack(struct LinkedStack* s, int x)//入栈
350{
351 struct Node* node =
352 malloc(sizeof(struct Node));
353
354 if (node == NULL) {
355 return 0;
356 }
357
358 node->data = x;
359 node->next = s->top;
360 s->top = node;
361
362 return 1;
363}
364
365int PopLinkedStack(struct LinkedStack* s, int* x)//出栈
366{
367 if (IsLinkedStackEmpty(s)) {
368 return 0;
369 }
370
371 struct Node* p = s->top;
372
373 *x = p->data;
374
375 s->top = p->next;
376
377 free(p);
378
379 return 1;
380}
381
382int GetLinkedStackTop(struct LinkedStack* s, int* x)//查看栈顶
383{
384 if (IsLinkedStackEmpty(s)) {
385 return 0;
386 }
387
388 *x = s->top->data;
389
390 return 1;
391}
392
393十一、链式栈例子
394
395初始:top = NULL
396
397入栈 10:
398
399top
400 ↓
40110 -> NULL
402
403入栈 20:
404
405top
406 ↓
40720 -> 10 -> NULL
408
409入栈 30:
410
411top
412 ↓
41330 -> 20 -> 10 -> NULL
414
415出栈:
416
417弹出 30
418top 指向 20
419
420变成:
421
422top
423 ↓
42420 -> 10 -> NULL
425
426十二、顺序栈和链式栈
427类型 存储方式 优点 缺点
428顺序栈 数组 简单、访问快 容量固定
429
430链式栈 链表 容量灵活 需要 malloc/free
431
432栈的常见算法题
433
434栈常用于:
4351. 括号匹配
4362. 表达式求值
4373. 单调栈
4384. 递归转非递归
4395. DFS
4406. 函数调用栈
4417. 浏览器前进后退
4428. 字符串消除
443
444
445顺序栈优点:
446 简单,速度快。
447
448顺序栈缺点:
449 容量固定。
450
451链式栈优点:
452 容量灵活。
453
454链式栈缺点:
455 需要动态申请和释放内存。
456
457栈就是只能在一端操作的线性表,规则是后进先出。
栈 Stack ADT
一、前提条件:栈是一种线性表。
它的特点是:只能在一端插入和删除。
这一端叫:栈顶 top
另一端叫:栈底 bottom
二、核心概念
栈的规则是:后进先出 LIFO
也就是:Last In First Out
例如依次入栈:
1
2
3
栈内逻辑是:
栈顶
↓
3
2
1
先进的扔到栈底,后进的在栈顶
出栈顺序是:
3 -> 2 -> 1
三、基本操作
栈 ADT 常见操作:
InitStack 初始化栈
Push 入栈
Pop 出栈
GetTop 取栈顶元素
IsEmpty 判空
IsFull 判满
四、顺序栈
- 存储结构:用数组实现。
#define MAXSIZE 100
struct Stack {
int data[MAXSIZE];
int top;
};
这里:
data 存元素
top 表示栈顶下标
- top 的定义
常见写法:top = -1 表示空栈
如果压入第一个元素:
top = 0
栈:
data[0]
如果再压入一个:
top = 1
栈:
data[0], data[1]
所以:top 永远指向当前栈顶元素。
五、顺序栈 C 语言模板
-
初始化
void InitStack(struct Stack* s)
{
s->top = -1;
}
-
判空
int IsEmpty(struct Stack* s)
{
return s->top == -1;
}
-
判满
int IsFull(struct Stack* s)
{
return s->top == MAXSIZE - 1;
}
-
入栈 Push
int Push(struct Stack* s, int x)
{
if (IsFull(s)) {
return 0;
}
s->top++;
s->data[s->top] = x;
return 1;
}
也可以写成:
s->data[++s->top] = x;
-
出栈 Pop
int Pop(struct Stack* s, int* x)
{
if (IsEmpty(s)) {
return 0;
}
*x = s->data[s->top];
s->top--;
return 1;
}
这里用:int* x
是为了把出栈元素带回去。
-
读取栈顶 GetTop
int GetTop(struct Stack* s, int* x)
{
if (IsEmpty(s)) {
return 0;
}
*x = s->data[s->top];
return 1;
}
注意:
GetTop 只读取,不删除。
Pop 读取并删除。
六、顺序栈完整代码
#define MAXSIZE 100
struct Stack {
int data[MAXSIZE];
int top;
};
void InitStack(struct Stack* s)
{
s->top = -1;
}
int IsEmpty(struct Stack* s)
{
return s->top == -1;
}
int IsFull(struct Stack* s)
{
return s->top == MAXSIZE - 1;
}
int Push(struct Stack* s, int x)
{
if (IsFull(s)) {
return 0;
}
s->top++;
s->data[s->top] = x;
return 1;
}
int Pop(struct Stack* s, int* x)
{
if (IsEmpty(s)) {
return 0;
}
*x = s->data[s->top];
s->top--;
return 1;
}
int GetTop(struct Stack* s, int* x)
{
if (IsEmpty(s)) {
return 0;
}
*x = s->data[s->top];
return 1;
}
七、顺序栈例子
初始:top = -1
栈为空
执行:Push(&s, 10);
变成:
data[0] = 10
top = 0
执行:Push(&s, 20);
变成:
data[0] = 10
data[1] = 20
top = 1
栈顶是:20
执行:Pop(&s, &x);
得到:
x = 20
top = 0
栈里剩:10
八、链式栈
顺序栈用数组,有最大容量限制。
链式栈用链表,没有固定容量限制。
- 存储结构
struct Node {
int data;
struct Node* next;
};
struct LinkedStack {
struct Node* top;
};
这里:top 指向链表第一个节点。
也就是:链表头部就是栈顶。
九、链式栈 C 语言模板
- 初始化
void InitLinkedStack(struct LinkedStack* s)
{
s->top = NULL;
}
- 判空
int IsLinkedStackEmpty(struct LinkedStack* s)
{
return s->top == NULL;
}
- 入栈 Push
链式栈入栈本质是:
头插法
#include <stdlib.h>
int PushLinkedStack(struct LinkedStack* s, int x)
{
struct Node* node =
malloc(sizeof(struct Node));
if (node == NULL) {
return 0;
}
node->data = x;
node->next = s->top;
s->top = node;
//这里相当于是把node的next赋NULL,之后把top指向node,每次头插进之后,top都指向新的node,
return 1;
}
- 出栈 Pop
链式栈出栈本质是:
删除头节点
int PopLinkedStack(struct LinkedStack* s, int* x)
{
if (IsLinkedStackEmpty(s)) {
return 0;
}
struct Node* p = s->top;
*x = p->data;
s->top = p->next;
//相当于就是把top对应的值返回给x,然后top去取next的值,这样相当于把原节点跳过
free(p);
return 1;
}
-
读取栈顶
int GetLinkedStackTop(struct LinkedStack* s, int* x)
{
if (IsLinkedStackEmpty(s)) {
return 0;
}
*x = s->top->data;
return 1;
}
十、链式栈完整代码
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
struct LinkedStack {
struct Node* top;
};
void InitLinkedStack(struct LinkedStack* s)
{
s->top = NULL;
}
int IsLinkedStackEmpty(struct LinkedStack* s)
{
return s->top == NULL;
}
int PushLinkedStack(struct LinkedStack* s, int x)//入栈
{
struct Node* node =
malloc(sizeof(struct Node));
if (node == NULL) {
return 0;
}
node->data = x;
node->next = s->top;
s->top = node;
return 1;
}
int PopLinkedStack(struct LinkedStack* s, int* x)//出栈
{
if (IsLinkedStackEmpty(s)) {
return 0;
}
struct Node* p = s->top;
*x = p->data;
s->top = p->next;
free(p);
return 1;
}
int GetLinkedStackTop(struct LinkedStack* s, int* x)//查看栈顶
{
if (IsLinkedStackEmpty(s)) {
return 0;
}
*x = s->top->data;
return 1;
}
十一、链式栈例子
初始:top = NULL
入栈 10:
top
↓
10 -> NULL
入栈 20:
top
↓
20 -> 10 -> NULL
入栈 30:
top
↓
30 -> 20 -> 10 -> NULL
出栈:
弹出 30
top 指向 20
变成:
top
↓
20 -> 10 -> NULL
十二、顺序栈和链式栈
类型 存储方式 优点 缺点
顺序栈 数组 简单、访问快 容量固定
链式栈 链表 容量灵活 需要 malloc/free
栈的常见算法题
栈常用于:
- 括号匹配
- 表达式求值
- 单调栈
- 递归转非递归
- DFS
- 函数调用栈
- 浏览器前进后退
- 字符串消除
顺序栈优点:
简单,速度快。
顺序栈缺点:
容量固定。
链式栈优点:
容量灵活。
链式栈缺点:
需要动态申请和释放内存。
栈就是只能在一端操作的线性表,规则是后进先出。