


在数据结构的世界里,“栈” 是一个既基础又实用的概念。它就像我们日常生活中叠放的盘子 —— 只能从最上面拿取,也只能往最上面添加,这种 “后进先出”(LIFO,Last In First Out)的特性,让栈在程序开发中有着广泛的应用。今天我们就来重点聊聊栈的一种实现方式 ——顺序结构,用简单易懂的语言和实际代码案例,带你轻松掌握它的核心知识。
栈的顺序结构,本质上是用数组来实现的栈结构。我们知道数组是一块连续的内存空间,通过下标可以快速访问元素,利用这一特性,顺序栈能高效地完成 “入栈” 和 “出栈” 操作。
你可以把顺序栈想象成一个有固定容量的 “抽屉”:
结合开头给出的 C 语言代码案例,我们来逐一拆解顺序栈的核心操作。这些操作是顺序栈的灵魂,掌握它们就等于掌握了顺序栈的使用方法。
要实现顺序栈,首先得定义它的结构。在 C 语言中,我们通常用结构体来封装两个关键部分:存储元素的数组,以及标记栈顶位置的指针。
#define maxsize 100 // 定义栈的最大容量
typedef int elemtype; // 定义栈中元素的类型(这里是int)
// 栈的结构体定义
typedef struct {
elemtype data[maxsize]; // 存储元素的数组
int top; // 栈顶指针,标记当前栈顶下标
} stack;
这里的data[maxsize]就是我们的 “抽屉”,maxsize规定了抽屉的最大层数(最多能放 100 个元素);top是栈顶指针,它的取值直接反映了栈的状态:
使用栈之前,必须先进行初始化,也就是把栈顶指针设置为-1,表示这是一个空栈。
void initstack(stack* s) {
s->top = -1; // 栈顶指针置为-1,栈为空
}
这一步就像刚买的抽屉,打开时里面是空的,我们需要先确认它的 “初始状态”,避免后续操作出错。
入栈就是把新元素放到栈顶的操作,核心是 “移动栈顶指针→存入元素”。
elemtype pushstack(stack* s, elemtype e) {
if (s->top >= maxsize - 1) { // 先判断栈是否已满
printf("栈已满");
return 0; // 入栈失败
}
s->top++; // 栈顶指针上移(指向新的空位置)
s->data[s->top] = e; // 把元素存入新的栈顶位置
return 1; // 入栈成功
}
举个例子:如果当前栈是空的(top = -1),我们要把元素8入栈:
再入栈88时,top变成1,88存入data[1],栈顶更新为88—— 这就是 “后进” 的过程。
出栈是把栈顶元素取出并删除的操作,核心是 “取出元素→移动栈顶指针”,必须先判断栈是否为空(不能从空抽屉里拿东西)。
elemtype popstack(stack* s, elemtype* e) {
if (s->top == -1) { // 判断栈是否为空
printf("是空的");
return 0; // 出栈失败
}
*e = s->data[s->top]; // 把栈顶元素存入e,供外部使用
s->top--; // 栈顶指针下移,相当于删除栈顶元素
return 1; // 出栈成功
}
还是刚才的例子,栈里有8、88、888三个元素(top = 2):
有时候我们只想知道栈顶是什么元素,不想删除它,这时候就需要 “获取栈顶元素” 的操作,和出栈类似,但不移动栈顶指针。
elemtype gettop(stack* s, elemtype* e) {
if (s->top == -1) { // 判断栈是否为空
printf("是空的");
return 0;
}
*e = s->data[s->top]; // 取出栈顶元素,但不改变top的值
return 1;
}
比如上面出栈888后,用这个函数就能获取到当前栈顶88,而栈的结构不会发生变化。
为了避免操作空栈,我们需要一个函数来判断栈是否为空,本质就是检查top是否等于-1。
elemtype is_empty(stack* s) {
if (s->top == -1) {
printf("是空栈\n");
return 1; // 是空栈
} else {
return 0; // 不是空栈
}
}
我们把上面的操作串联起来,看看完整的运行过程(对应代码中的 main 函数):
int main() {
stack s; // 定义一个栈
initstack(&s); // 初始化栈(top = -1)
pushstack(&s,8); // 入栈8 → top=0,data[0]=8
pushstack(&s,88); // 入栈88 → top=1,data[1]=88
pushstack(&s,888);// 入栈888 → top=2,data[2]=888
elemtype e;
popstack(&s,&e); // 出栈 → 取出888,top=1
printf("%d\n",e); // 输出:888
gettop(&s,&e); // 获取栈顶 → 取出88,top仍为1
printf("%d\n",e); // 输出:88
}
运行结果就是先后输出888和88,完全符合 “后进先出” 的规则 —— 最后入栈的888最先出栈,剩下的栈顶就是88。
顺序栈适合元素数量固定、操作频繁的场景,比如:
栈的顺序结构是数据结构入门的重要知识点,它的核心是 “数组 + 栈顶指针” 的组合,通过简单的指针移动实现 “后进先出” 的特性。今天我们从定义、核心操作、实际案例到应用场景,全方位拆解了顺序栈的知识,关键要点可以总结为:
如果你是编程新手,建议结合本文的代码案例,自己动手敲一遍代码,运行调试看看效果 —— 实践是掌握数据结构最好的方式。下一篇我们可以聊聊栈的另一种实现方式 —— 链式结构,看看它如何解决顺序栈容量固定的问题,感兴趣的小伙伴可以持续关注哦!