跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C算法

数据结构:顺序栈(Stack)详解

栈(Stack)这一线性表的数据结构,重点阐述了其后进先出(LIFO)的特性及基本操作。内容包括顺序栈的结构定义、初始化、入栈、出栈、获取栈顶元素等核心功能的 C 语言实现代码。此外,还探讨了双栈共享空间的优化策略,利用数组两端向中间延伸的方式提高内存利用率。文章提供了完整的代码示例及遍历方法,适合初学者掌握栈的基础原理与应用。

PgDevote发布于 2026/3/22更新于 2026/10/2495 浏览
数据结构:顺序栈(Stack)详解

一、栈的定义

栈(stack)是限定仅在表尾进行插入和删除操作的线性表。

文章配图

我们把允许插入和删除的一端成为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈称为空栈。栈又称为后进先出(Last In First Out)的线性表,简称LIFO 结构。

栈的插入操作,叫做进栈,也称压栈,入栈。

栈的删除操作,叫做出栈,也叫做弹栈。

二、对栈的操作

由于栈本身就是一个线性表,那么我们上一章讨论的线性表的顺序存储和链式存储,对于栈来说同样适用。

InitStack (*s):初始化操作,建立一个空栈 s。

DestroyStack (*s) :若栈存在,则销毁它。

ClearStack(*s):将栈清空。

StackEmpty(s):若栈为空,返回 true,否则返回 false。

GetTop(s,*e):若栈存在且非空,用 e 返回 s 的栈顶元素。

Push (*s,e) :若栈存在,插入新元素 e 到 s 中并成为栈顶元素。

Pop(*s,*e):删除 s 中的栈顶元素,并用 e 返回其值。

StackLength(s):返回栈 s 的元素个数。

三、栈的顺序存储结构及实现

3.1、栈的顺序存储结构

栈的结构定义。

typedef int SElemType; //元素类型根据实际情况而定,这里假设为 int
//顺序栈结构
typedef struct{
    SElemType data[MAXSIZE];
    int top; //用于栈顶指针
}SqStack;

构造一个空栈 s。

Status InitStack(SqStack *s){
    s->data=(SElemType *)malloc(MAXSIZE*sizeof(SElemType));
    s->top=-1;
    return OK;
}

把 s 置为空栈。

Status ClearStack(SqStack *s){
    s->top=-1;
    return OK;
}

//若栈为空栈,返回 true,否则返回 false
Status StackEmpty (SqStack s){
    if(s->top==-1){
        return true;
    }
    return false;
}

返回栈 s 的元素个数,即栈的长度

int StackLength(SqStack s){
    return s.top+1;
}

若栈不空,则用 e 返回 s 的栈顶元素,并返回 OK,否则返回 ERROR

Status GetTop(SqStack s,SElemType *e){
    if(s.top==-1){
        return ERROR;
    } else{
        *e=s.data[s->top];
        return OK;
    }
}

插入元素 e 为新的栈顶元素

Status Push(SqStack *s,SElemType e){
    if(s->top==MAXSIZE-1){ //栈满
        return ERROR;
    }
    s->top++; //栈顶指针加一
    s->data[s->top]=e; //将新插入元素赋值给栈顶空间
    return OK;
}

删除 s 的栈顶元素

//若栈不空,则删除 s 的栈顶元素,用 e 返回其值,并返回 OK,否则返回 ERROR
Status Pop(SqStack *s,SElemType *e){
    if(s->top==-1){
        return ERROR;
    }
    *e=s->data[s->top]; //将要删除的栈顶元素赋值给 e
    s->top--; //栈顶指针减一
    return OK;
}

遍历顺序栈

Status StackTraverse(SqStack s){
    int i=0;
    while(i<=s.top){
        visit(s.data[i++]);
    }
    printf("\n");
    return OK;
}

3.2、顺序栈的运用 代码示例

int main(){
    int j;
    SqStack s;
    int e;
    if(InitStack(&s)==OK){
        for(j=1;j<=10;j++){
            Push(&s,j);
        }
        printf("栈中元素依次为: ");
        StackTraverse(s);
        Pop(&s,&e);
        printf("弹出的元素 e=%d\n",e);
        printf("栈空否:%d(1 空 0 否)",StackEmpty(s));
        GetTop(s,&e);
        printf("栈顶元素 e=%d 栈的长度为%d\n",e,StackLength(s));
        ClearStack(&s);
        printf("清空栈后,栈空否:%d(1 空 0 否)\n",StackEmpty(s));
    }
    return 0;
}

四、两栈共享空间

栈的顺序存储只准栈顶进出元素,所以不存在线性表插入和删除时需要移动元素的问题。不过有一个很大的缺陷就是:必须事先确定数组存储空间大小,非常麻烦。

对于两个相同类型的栈,我们可以用一个数组来存储,充分利用数组的内存空间。

文章配图

我们的做法如下:让一个栈的栈底为数组的始端,即下标为 0 处,另一个栈为数组的末端,即下标为数组长度 n-1 处。这样,两个栈如果增加元素,就是两端点向中间延伸。

  1. top1 和 top2 是栈 1 和栈 2 的栈顶指针。
  2. 若栈 2 是空栈,栈 1 的 top1=n-1 时,就是栈 1 满了
  3. 若栈 1 是空栈,栈 2 的 top2=0 时,就是栈 2 满了
  4. 两个栈见面之时,也就是两个指针相差 1 时,即 top1+1=top2 为栈满
//两栈共享空间结构
typedef struct{
    SElemType data[MAXSIZE];
    int top1; //栈 1 栈顶指针
    int top2; //栈 2 栈顶指针
}SqDoubleStack;

Status visit(SElemType c){
    printf("%d",c);
    return OK;
}

构造一个空栈 s / 把 s 置为空栈

Status InitStack(SqDoubleStack *s){
    s->top1=-1;
    s->top2=MAXSIZE;
    return OK;
}

若 s 为空栈,返回 true,否则返回 false

Status StackEmptyStack(SqDoubleStack s){
    if(s.top1==-1&&s.top2==MAXSIZE){
        return true;
    } else{
        return false;
    }
}

返回 s 的元素个数,即栈的长度

int StackLength(SqDoubleStack s){
    return s.top1+1+(MAXSIZE-s.top2);
}

插入元素 e 为新的栈顶元素

Status Push(SqDoubleStack *s,SElemType e,int StackNumber){
    if(s->top1+1==s->top2){
        return ERROR; //栈已满,不能再 push 新元素了
    }
    if(StackNumber==1){ //栈 1 有元素进栈
        s->data[++s->top1]=e; //是栈 1 则先 top1+1 再给数组元素赋值
    } else if(StackNumber==2){ //栈 2 有元素进栈
        s->data[--s->top2]=e; //是栈 2 则先 top2-1 再给数组元素赋值
    }
    return OK;
}

删除 s 的栈顶元素,用 e 返回其值

Status Pop(SqDoubleStack *s,SElemType *e,int StackNumber){
    if(StackNumber==1){
        if(s->top1==-1){
            return ERROR; //说明栈 1 是空栈,溢出
        }
        *e=s->data[s->top1--]; //将栈 1 的栈顶元素出栈
    } else if(StackNumber==2){
        if(s->top2==MAXSIZE){
            return ERROR; //说明栈 2 是空栈,溢出
        }
        *e=s->data[s->top2++]; //将栈 2 的栈顶元素出栈
    }
    return OK;
}

遍历

Status StackTraverse(SqDoubleStack s){
    int i=0;
    while(i<=s.top1){
        visit(s.data[i++]);
    }
    i=s.top2;
    while(i<MAXSIZE){
        visit(s.data[i++]);
    }
    printf("\n");
    return OK;
}

小结:事实上,使用这样的数据结构,通常都是两个栈的空间需求有相反关系时,也就是一个栈在增长另一个栈在缩短的情况

参考资料:程杰:《大话数据结构》

目录

  1. 一、栈的定义
  2. 二、对栈的操作
  3. 三、栈的顺序存储结构及实现
  4. 3.1、栈的顺序存储结构
  5. 3.2、顺序栈的运用 代码示例
  6. 四、两栈共享空间

更多推荐文章

查看全部
  • 飞算 JavaAI 实战指南:用自然语言加速 Java 开发
  • 利用 AI 视觉模型优化 Unity 编辑器插件:从功能实现到界面美化
  • RustDesk 服务端完整安装部署教程
  • Unity VR 高分辨率全景视频播放性能优化方案
  • Android 开发面试核心知识点与八股文精选题解
  • Ubuntu 服务器安装 lrzsz 工具实现文件传输
  • 基于 LLaMA-Factory 与 LoRA 微调 GPT-OSS-20B 模型实战
  • 精选 GitHub 上 7 款热门 Claude Skills 开源工具
  • 飞书 OpenClaw 机器人配置指南:实现 AI 智能对话与自动化办公
  • Linux 环境变量详解:概念、操作与代码获取
  • CSS3 十六进制透明度实战:#RRGGBBAA 用法与避坑指南
  • 算法优选:位运算技巧与实战案例
  • 数据结构与算法:随机链表复制的三步解法
  • AI 产品经理入门:大模型关键知识与落地逻辑
  • C++ 面向对象:深入解析继承机制
  • 本地 AI 绘图实战:Z-Image-Turbo_UI 界面体验与性能测试
  • Token 管理实践:前端登录凭证的获取、存储与过期处理
  • Midjourney 官网地址及中文支持情况说明
  • Llama 3.3 70B 模型部署输出异常排查与优化指南
  • VisionTransformer(ViT)在时间序列行为识别中的应用

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online