首页/数据结构/03-stack-queue-array/栈的基本操作 🔗 在 Obsidian 中打开
数据结构 · 03-stack-queue-array

栈的基本操作

难度 ★★重要度 ★★★★★ 考查频率 高题型 选择 / 算法 顺序栈链栈LIFO
速查
栈是只允许在栈顶插入删除的线性表,遵循 LIFO。顺序栈 top 从 −1 起,入栈先加后存、出栈先取后减;n 个元素入栈的出栈序列数 = 卡特兰数 C(2n,n)/(n+1)

核心概念

定义

栈是只允许在一端(栈顶)进行插入和删除的线性表。

  • LIFO:后进先出(Last In First Out)
  • 栈顶(Top):允许操作的一端
  • 栈底(Bottom):不允许操作的一端

栈的操作

  • Push:入栈,在栈顶插入
  • Pop:出栈,删除栈顶
  • GetTop:取栈顶(不出栈)

一、顺序栈

#define MaxSize 50
typedef struct {
    ElemType data[MaxSize];
    int top;  // 栈顶指针(下标)
} SqStack;

初始化 / 判空

void InitStack(SqStack *S) { S->top = -1; }
bool StackEmpty(SqStack S) { return (S.top == -1); }

入栈

bool Push(SqStack *S, ElemType x) {
    if (S->top == MaxSize - 1) return false;  // 栈满
    S->data[++S->top] = x;                    // 先加后存
    return true;
}

出栈

bool Pop(SqStack *S, ElemType *x) {
    if (S->top == -1) return false;  // 栈空
    *x = S->data[S->top--];          // 先取后减
    return true;
}

读栈顶

bool GetTop(SqStack S, ElemType *x) {
    if (S.top == -1) return false;
    *x = S.data[S.top]; return true;
}
注意top 指向栈顶元素:栈空 $top==-1$,栈满 $top==MaxSize-1$,元素个数 $top+1$。

二、共享栈(两栈共享空间)

#define MaxSize 50
typedef struct { ElemType data[MaxSize]; int top1, top2; } ShStack;
void InitShStack(ShStack *S) { S->top1 = -1; S->top2 = MaxSize; }
  • 栈 1 从前往后增长,栈 2 从后往前增长
  • 栈满:$ top1 + 1 == top2 $
  • 栈 1 空:$ top1 == -1 $,栈 2 空:$ top2 == MaxSize $

三、链栈

typedef struct LinkNode {
    ElemType data;
    struct LinkNode *next;
} LinkNode, *LiStack;

初始化 / 入栈(头插)/ 出栈

void InitLiStack(LiStack *S) { *S = NULL; }   // 不带头结点
void Push(LiStack *S, ElemType x) {            // 头插法
    LinkNode *p = (LinkNode *)malloc(sizeof(LinkNode));
    p->data = x; p->next = *S; *S = p;
}
bool Pop(LiStack *S, ElemType *x) {
    if (*S == NULL) return false;
    LinkNode *p = *S; *x = p->data; *S = p->next; free(p); return true;
}
链栈特点无需判满(动态分配);入栈出栈都在表头 O(1);通常不需要头结点。

关键对比

特性顺序栈链栈
存储方式连续离散
栈满判断$ top==MaxSize-1 $无(动态分配)
空间复杂度固定动态
入栈出栈O(1)O(1)

手算示例

例 1:入栈出栈序列

元素 1,2,3 依次入栈,合法出栈序列:1,2,3 / 1,3,2 / 2,1,3 / 2,3,1 / 3,2,1。不可能 3,1,2(3 出栈时 1,2 在栈中且 2 在 1 上)。

例 2:出栈序列合法性

入栈 1,2,3,4,5,判断 4,3,5,1,2:入 1,2,3,4→出 4→出 3→入 5→出 5→需出 1 但 2 在 1 上 → 不合法

例 3:卡特兰数

n 个不同元素入栈,出栈序列数 = $ C(2n,n)/(n+1) $。

常见考法

高频设问
  • 出栈序列合法性:模拟入栈出栈过程。
  • 操作序列输出:给定 IIIOOIOO 求输出。
  • 共享栈满:$ top1+1==top2 $。
  • 卡特兰数:出栈序列数 $ C(2n,n)/(n+1) $。

易错点

必记
  1. top 含义:指向栈顶元素,不是下一个位置。
  2. 先加后存 vs 先取后减data[++top] vs data[top--]
  3. 共享栈满:不是 $ top1==top2 $,而是 $ top1+1==top2 $。
  4. 链栈判空:$ *S==NULL $(不带头结点)。
  5. 出栈顺序:不能跳过栈顶直接取下面的。

核心结论

必背
  1. 顺序栈:top 从 −1 起,入栈先加后存、出栈先取后减。
  2. 共享栈:两端向中间增长,$ top1+1==top2 $ 为满。
  3. 链栈:头插法入栈,头部删除出栈,无需判满。
  4. 卡特兰数:n 元素入栈,出栈序列数 $ C(2n,n)/(n+1) $。

记忆卡片

顺序栈栈空/栈满条件?
空 $top==-1$,满 $top==MaxSize-1$。
入栈 `++top` 为何在前面?
先将 top 加 1 再存元素(先加后存)。
共享栈栈满条件?
$ top1 + 1 == top2 $。
n 元素入栈出栈序列数?
卡特兰数 $ C(2n,n)/(n+1) $。
链栈用头插还是尾插?
头插法,栈顶在表头,入出均 O(1)。
链栈判空条件?
$ *S==NULL $(不带头结点)。

交互动画 · 栈的入栈/出栈

顺序栈(top 从 −1 起,栈底在下)
点击「入栈」压入元素
橙色高亮 = 已入栈;top 指针指向栈顶元素(最上方)。

相关知识点

stack-and-queue-applications queue-basic-operations shared-stack

↑ 以上为站内 HTML 相对链接(纯网页可浏览);本页右上「在 Obsidian 中打开」跳回源笔记。