栈(Stack)是数据结构中的重要概念,也是计算机考研(如408统考)的常考点。本文结合王道考研资料和常见知识点,整理栈的基本概念、实现方式、操作细节及常考题型,帮助考生高效复习。
一、栈的基本概念
栈是一种操作受限的线性表,只允许在一端进行插入或删除操作 。其核心特性是后进先出(LIFO, Last In First Out)。
-
栈顶:允许插入和删除的一端。
-
栈底:不允许操作的一端。
-
空栈:没有元素的栈。
栈的逻辑结构与普通线性表相同,但运算受限,仅支持栈顶操作。基本操作包括:
-
InitStack(&S)
:初始化栈。 -
DestroyStack(&S)
:销毁栈。 -
Push(&S, x)
:进栈(插入元素)。 -
Pop(&S, &x)
:出栈(删除并返回元素)。 -
GetTop(S, &x)
:读栈顶元素(不删除)。 -
StackEmpty(S)
:判空。
栈的典型应用包括函数调用、表达式求值、括号匹配等,考研中常考察其特性和操作细节。
二、顺序栈的实现
顺序栈使用数组实现栈的存储,分配连续内存空间。
1. 顺序栈的定义
#define MaxSize 10 // 定义栈的最大容量
typedef struct {
ElemType data[MaxSize]; // 静态数组存放元素
int top; // 栈顶指针,指向栈顶元素
} SqStack;
-
top
通常初始化为-1
(表示空栈),指向当前栈顶元素的位置。 -
内存分配大小为
MaxSize * sizeof(ElemType)
。
2. 基本操作
-
进栈操作(Push):
先移动指针,再存入元素。
bool Push(SqStack &S, ElemType x) { if (S.top == MaxSize - 1) return false; // 栈满报错 S.top++; // 指针先加1 S.data[S.top] = x; // 再存入元素 return true; }
-
出栈操作(Pop):
先返回元素,再移动指针。
bool Pop(SqStack &S, ElemType &x) { if (S.top == -1) return false; // 栈空报错 x = S.data[S.top]; // 先返回栈顶元素 S.top--; // 指针再减1 return true; }
-
读栈顶元素(GetTop):
与出栈类似,但不移动指针。
bool GetTop(SqStack S, ElemType &x) { if (S.top == -1) return false; x = S.data[S.top]; return true; }
3. 共享栈
为节省空间,可让两个栈共享同一数组:
typedef struct {
ElemType data[MaxSize];
int top0; // 0号栈指针(初始为-1)
int top1; // 1号栈指针(初始为MaxSize)
} ShStack;
-
栈满条件 :
top0 + 1 == top1
。 -
初始化时,
top0 = -1
,top1 = MaxSize
。
三、链栈的实现
链栈使用链表实现栈的存储,无需预设大小,动态分配内存。
1. 链栈的定义
typedef struct Linknode {
ElemType data; // 数据域
struct Linknode *next; // 指针域
} *LiStack; // 栈类型定义
- 通常用头插法模拟进栈操作,类似单链表的插入。
2. 基本操作
-
进栈(Push):
对应单链表的头插法,在头部插入新节点。
// 类似后插操作 bool Push(LiStack &S, ElemType e) { Linknode *s = (Linknode *)malloc(sizeof(Linknode)); if (!s) return false; s->data = e; s->next = S; // S为头指针 S = s; // 更新头指针 return true; }
-
出栈(Pop):
对应单链表的头删操作,删除头节点并返回元素。
bool Pop(LiStack &S, ElemType &x) { if (S == NULL) return false; // 栈空 Linknode *p = S; x = p->data; S = p->next; free(p); return true; }
-
其他操作:
-
GetTop
:读取头节点数据。 -
StackEmpty
:判断头指针是否为空。
-
链栈的优点是无栈满问题(除非内存耗尽),但需额外空间存储指针。
四、栈的常考题型与应用
1. 出栈顺序问题
-
问题:给定进栈顺序(如 a→b→c→d→e),求合法出栈顺序。
-
考点:卡特兰数(Catalan数)公式:
表示 n个不同元素的出栈排列数。例如,3个元素有5种合法出栈顺序。
-
解题技巧:使用栈模拟过程,避免非法顺序(如中间元素先出)。
2. 应用场景
-
递归函数调用:系统栈管理调用记录。
-
表达式求值:中缀转后缀,利用栈处理运算符优先级。
-
括号匹配:遇左括号进栈,遇右括号出栈检查。
-
考研高频考点:操作序列合法性、栈的初始状态分析等。
五、总结与复习建议
知识回顾
-
逻辑结构:线性表的特例,LIFO特性。
-
存储结构:
-
顺序栈:数组实现,需预设大小,操作高效。
-
链栈:链表实现,动态扩容,灵活但开销大。
-
-
重要考点:基本操作实现、共享栈、出栈序列、应用场景。
复习建议
-
动手练习:编写顺序栈和链栈的代码,模拟进栈出栈过程。
-
题型突破:重点练习出栈顺序题,结合卡特兰数理解。
-
知识输出:尝试向他人讲解栈的操作,巩固记忆(如王道考研提到的"知识输出"理念)。
-
模拟考试:定期刷考研真题,关注408统考中栈的相关题目。
本文基于王道考研资料整理,结合常见考研重点,助你高效备考。栈是基础数据结构,掌握其实现和应用对后续学习(如队列、树)至关重要。