返回 LeetCode 刷题

Markdown File

栈ADT

栈ADT.md

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栈就是只能在一端操作的线性表,规则是后进先出。
Rendered Preview

栈 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 判满

四、顺序栈

  1. 存储结构:用数组实现。

#define MAXSIZE 100

struct Stack {
int data[MAXSIZE];
int top;
};

这里:
data 存元素
top 表示栈顶下标

  1. top 的定义

常见写法:top = -1 表示空栈

如果压入第一个元素:

top = 0

栈:

data[0]

如果再压入一个:

top = 1

栈:

data[0], data[1]

所以:top 永远指向当前栈顶元素。

五、顺序栈 C 语言模板

  1. 初始化
    void InitStack(struct Stack* s)
    {
    s->top = -1;
    }

  2. 判空
    int IsEmpty(struct Stack* s)
    {
    return s->top == -1;
    }

  3. 判满
    int IsFull(struct Stack* s)
    {
    return s->top == MAXSIZE - 1;
    }

  4. 入栈 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;

  1. 出栈 Pop
    int Pop(struct Stack* s, int* x)
    {
    if (IsEmpty(s)) {
    return 0;
    }

    *x = s->data[s->top];
    s->top--;

    return 1;
    }

这里用:int* x

是为了把出栈元素带回去。

  1. 读取栈顶 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

八、链式栈

顺序栈用数组,有最大容量限制。

链式栈用链表,没有固定容量限制。

  1. 存储结构

struct Node {
int data;
struct Node* next;
};

struct LinkedStack {
struct Node* top;
};

这里:top 指向链表第一个节点。

也就是:链表头部就是栈顶。

九、链式栈 C 语言模板

  1. 初始化
    void InitLinkedStack(struct LinkedStack* s)
    {
    s->top = NULL;
    }
  2. 判空
    int IsLinkedStackEmpty(struct LinkedStack* s)
    {
    return s->top == NULL;
    }
  3. 入栈 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;
}

  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;

}

  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

栈的常见算法题

栈常用于:

  1. 括号匹配
  2. 表达式求值
  3. 单调栈
  4. 递归转非递归
  5. DFS
  6. 函数调用栈
  7. 浏览器前进后退
  8. 字符串消除

顺序栈优点:
简单,速度快。

顺序栈缺点:
容量固定。

链式栈优点:
容量灵活。

链式栈缺点:
需要动态申请和释放内存。

栈就是只能在一端操作的线性表,规则是后进先出。