【数据结构】用C语言实现顺序栈(附完整运行代码)

🦄个人主页:修修修也

🎏所属专栏:数据结构

⚙️操作环境:Visual Studio 2022


一.了解项目功能

在本次项目中我们的目标是实现一个顺序栈:

顺序栈使用动态内存分配空间,可以用来存储任意数量的同类型数据.

顺序栈结构体需要包含三个要素:存放数据的数组arr,栈顶元素下标top,栈容量capacity.

顺序栈程序提供的功能有:

  1. 顺序栈的初始化
  2. 顺序栈的销毁
  3. 顺序栈的入栈
  4. 顺序栈的出栈
  5. 顺序栈的长度
  6. 顺序栈判空
  7. 顺序栈取栈顶元素

二.项目功能演示

要编写一个顺序栈项目,首先要明确我们想要达到的效果是什么样,下面我将用vs2022编译器来为大家演示一下顺序栈程序运行时的样子:

顺序栈的C语言实现


三.逐步实现项目功能模块及其逻辑详解

通过第二部分对项目功能的介绍,我们已经对顺序栈的功能有了大致的了解,虽然看似需要实现的功能很多,貌似一时间不知该如何下手,但我们可以分步分模块来分析这个项目的流程,最后再将各部分进行整合,所以大家不用担心,跟着我一步一步分析吧!


!!!注意,该部分的代码只是为了详细介绍某一部分的项目实现逻辑,故可能会删减一些与该部分不相关的代码以便大家理解,需要查看或拷贝完整详细代码的朋友可以移步本文第四部分。


1.实现顺序栈程序菜单

菜单部分的逻辑比较简单,就是利用C语言printf函数打印出这个菜单界面即可。但要注意菜单的标序要和后续switch...case语句的分支相应,以免导致后续执行语句错乱的问题.基础问题就不过多赘述了,代码如下:

该部分功能实现代码如下: 

void STMenu()
{printf("**********************************\n");printf("******请选择要进行的操作    ******\n");printf("******1.顺序栈入栈          ******\n");printf("******2.顺序栈出栈          ******\n");printf("******3.取栈顶元素          ******\n");printf("******4.判断栈空            ******\n");printf("******5.查询当前栈长        ******\n");printf("******6.清空顺序栈          ******\n");printf("******7.销毁顺序栈          ******\n");printf("******0.退出顺序栈程序      ******\n");printf("**********************************\n");printf("请选择:>");}

2.实现顺序栈程序功能可循环使用

由于我们要实现顺序栈的功能可以反复使用的逻辑,且至少在一开始执行一次,因此我们选择do...while的循环语句来实现这一部分的逻辑.

该部分功能实现代码如下:

int main()
{ST st;STInit(&st);int swi = 0;//创建变量swi作为do...while循环的终止条件,以及switch语句的运行条件do          //使用do...while实现{STMenu();scanf("%d", &swi);switch (swi){case 0:STDestroy(&st);printf("您已退出程序:>\n");// 释放链表内存break;case 1:printf("请输入要入栈的数据:>");STDataType pushback_data = 0;scanf("%d", &pushback_data);STPush(&st, pushback_data);printf("已成功入栈:>\n");break;case 2:printf("栈顶元素%d已成功出栈\n", STTop(&st));STPop(&st);break;case 3:printf("栈顶元素为:");STDataType sttop = STTop(&st);printf("%d\n", sttop);break;case 4:if (!STEmpty(&st)){printf("当前栈不为空\n");}else{printf("当前栈为空栈\n");}break;case 5:printf("当前栈长为:");int stsize = STSize(&st);printf("%d\n", stsize);break;case 6:STDestroy(&st);STInit(&st);printf("顺序栈已清空:>\n");break;case 7:STDestroy(&st);printf("顺序栈已销毁:>\n");break;default:printf("输入错误,请重新输入\n");break;}} while (swi);return 0;
}

3.创建顺序栈

创建顺序栈成员的结构体应该包括:存放数据的数组arr,栈顶元素下标top,栈容量capacity.

因此我们创建Stack结构体类型时应由一个数组及两个整型组成.

这里的第9行使用的typedef类定义的作用是方便我们后续在使用顺序栈时对存储的数据类型做更改,比如后续我们不想存储int类型数据了,就可以很方便的在这里对数组类型做更改.比如改成char类型,或者double类型,甚至改成任意自己构造的结构类型.

综上,该部分代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>typedef int STDataType;typedef struct Stack
{int *arr;int top;int capacity;
}ST;

4.初始化顺序栈

初始化顺序栈的逻辑和初始化顺序表一样,我们在初始化时为栈开辟4个数据类型的数组空间,然后将顺序栈的容量改为4,栈顶置为0即可.

该部分的功能实现代码如下:

void STInit(ST* ps)
{assert(ps);ps->arr = (STDataType*)malloc(sizeof(STDataType) * 4);if (ps->arr == NULL){perror("malloc fail::\n");return;}ps->capacity = 4;ps->top = 0;   //top表示栈顶元素的下一个//top指向栈顶元素的话,top给-1}

5.顺序栈的入栈

顺序栈在入栈时,需要先判断一下栈内元素是否已满,如果满了则需要给栈扩容.(如下代码5-18行均是在执行顺序栈查满扩容逻辑)

如果没满则将新元素赋值给栈顶指针top,再将top++,使其始终指向栈顶的下一个元素位置.

该部分的功能实现代码如下: 

void STPush(ST* ps, STDataType x)
{assert(ps);if (ps->top == ps->capacity)//扩容{STDataType* tmp = (STDataType*)realloc(ps->arr, sizeof(STDataType) * ps->capacity * 2);if (tmp == NULL){perror("realloc fail::\n");return;}ps->arr = tmp;ps->capacity *= 2;}ps->arr[ps->top] = x;ps->top++;}

6.顺序栈的出栈

顺序栈的出栈就相当于顺序表的尾删,那么我们同顺序表一样移动栈顶下标位置即可.

顺序表尾删示意图:

该部分的功能实现代码如下: 

void STPop(ST* ps)
{assert(ps);assert(!STEmpty(ps));ps->top--;
}

7.顺序栈取栈顶元素

根据我们之前的设定,栈为空时top=0:

那么当栈中进入一个元素时,top++后top=1,而栈顶元素a1的下标等于0,所以我们的top设计其实是指向栈顶元素的下一个位置的:

因此在取栈顶函数中,我们要返回的栈顶数组下标应该是top-1.

该部分的功能实现代码如下: 

STDataType STTop(ST* ps)
{assert(ps);assert(!STEmpty(ps));return ps->arr[ps->top - 1];
}

8.顺序栈的长度

因为top指向的是栈顶元素的下一个位置,因此top的大小正好是栈的长度,所以求栈长函数我们对ps断言后可以直接返回top.

该部分的功能实现代码如下:

int STSize(ST* ps)
{assert(ps);return ps->top;
}

9.顺序栈的判空

顺序栈判空的逻辑是:如果栈为空返回true(真),否则返回false(假).

因此我们还是拿top来判断,如果top=0,会return true,意味着栈为空.

否则会return false,意味着栈不为空.

该部分的功能实现代码如下:

bool STEmpty(ST* ps)//判空,为空则真
{assert(ps);return ps->top==0;
}

10.顺序栈的销毁

当我们使用完顺序栈想要退出程序时,就应该将之前动态开辟的内存释放掉,还给操作系统.即销毁顺序栈.

我们使用free()函数释放掉之前动态开辟的数组arr,然后将arr置为空指针,最后将top,capacity的值置为0即可.

该部分的功能实现代码如下:

void STDestroy(ST* ps)
{assert(ps);free(ps->arr);ps->arr = NULL;ps->top = 0;ps->capacity = 0;}

四.项目完整代码

我们将程序运行的代码分别在三个工程文件中编辑,完整代码如下:

test.c文件

#include"Stack.h"int main()
{ST st;STInit(&st);int swi = 0;//创建变量swi作为do...while循环的终止条件,以及switch语句的运行条件do          //使用do...while实现{STMenu();scanf("%d", &swi);switch (swi){case 0:STDestroy(&st);printf("您已退出程序:>\n");// 释放链表内存break;case 1:printf("请输入要入栈的数据:>");STDataType pushback_data = 0;scanf("%d", &pushback_data);STPush(&st, pushback_data);printf("已成功入栈:>\n");break;case 2:printf("栈顶元素%d已成功出栈\n", STTop(&st));STPop(&st);break;case 3:printf("栈顶元素为:");STDataType sttop = STTop(&st);printf("%d\n", sttop);break;case 4:if (!STEmpty(&st)){printf("当前栈不为空\n");}else{printf("当前栈为空栈\n");}break;case 5:printf("当前栈长为:");int stsize = STSize(&st);printf("%d\n", stsize);break;case 6:STDestroy(&st);STInit(&st);printf("顺序栈已清空:>\n");break;case 7:STDestroy(&st);printf("顺序栈已销毁:>\n");break;default:printf("输入错误,请重新输入\n");break;}} while (swi);return 0;
}

  Stack.c 文件

#include"Stack.h"void STInit(ST* ps)
{assert(ps);ps->arr = (STDataType*)malloc(sizeof(STDataType) * 4);if (ps->arr == NULL){perror("malloc fail::\n");return;}ps->capacity = 4;ps->top = 0;   //top表示栈顶元素的下一个//top指向栈顶元素的话,top给-1}void STDestroy(ST* ps)
{assert(ps);free(ps->arr);ps->arr = NULL;ps->top = 0;ps->capacity = 0;}void STPush(ST* ps, STDataType x)
{assert(ps);if (ps->top == ps->capacity)//扩容{STDataType* tmp = (STDataType*)realloc(ps->arr,sizeof(STDataType)*ps->capacity*2);if (tmp == NULL){perror("realloc fail::\n");return;}ps->arr = tmp;ps->capacity *= 2;}ps->arr[ps->top] = x;ps->top++;}void STPop(ST* ps)
{assert(ps);assert(!STEmpty(ps));ps->top--;
}int STSize(ST* ps)
{assert(ps);return ps->top;
}bool STEmpty(ST* ps)//判空,为空则真
{assert(ps);return ps->top==0;
}STDataType STTop(ST* ps)
{assert(ps);assert(!STEmpty(ps));return ps->arr[ps->top - 1];
}void STMenu()
{printf("**********************************\n");printf("******请选择要进行的操作    ******\n");printf("******1.顺序栈入栈          ******\n");printf("******2.顺序栈出栈          ******\n");printf("******3.取栈顶元素          ******\n");printf("******4.判断栈空            ******\n");printf("******5.查询当前栈长        ******\n");printf("******6.清空顺序栈          ******\n");printf("******7.销毁顺序栈          ******\n");printf("******0.退出顺序栈程序      ******\n");printf("**********************************\n");printf("请选择:>");
}

Stack.h文件

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>typedef int STDataType;typedef struct Stack
{int *arr;int top;int capacity;
}ST;void STInit(ST* ps);
void STDestroy(ST* ps);void STPush(ST* ps, STDataType x);
void STPop(ST* ps);int STSize(ST* ps);bool STEmpty(ST* ps);//判空,为空则真STDataType STTop(ST* ps);void STMenu();

结语

希望这篇顺序栈的C语言实现详解能对大家有所帮助,欢迎大佬们留言或私信与我交流.

学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!

相关文章推荐

【数据结构】什么是栈?

【数据结构】C语言实现顺序表万字详解(附完整运行代码)

【数据结构】C语言实现单链表万字详解(附完整运行代码)

【数据结构】C语言实现带头双向循环链表万字详解(附完整运行代码)

【实用编程技巧】不想改bug?初学者必须学会使用的报错函数assert!(断言函数详解)


数据结构栈与队列篇思维导图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/169609.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件测试 | MySQL 主键约束详解:保障数据完整性与性能优化

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

Maven总结

文章目录 为什么学习Maven?一、Maven项目架构管理工具二、Maven的下载安装及配置1.maven的下载2.maven目录结构3.配置阿里云镜像和本地仓库:4.maven配置环境变量。5.阿里云镜像和本地仓库说明 三、idea中maven的操作1.以模板的形式创建maven项目2.其他配置maven的方式3.不勾模…

基础C语言编程题

int i,j; int a[3][3]; for(i0;i<3;i){for(j0;j<3;j){scanf("%d",&a[i][j]);a[i][j]a[i][j]*2;}} 6.功能&#xff1a;把20个随机数存入一个数组&#xff0c;然后输出该数组中的最大值。 int main(){int p[20];int i,max0;for(i0;i<20;i){scanf("…

浅谈现代化城市建设中智慧消防的研究与应用

安科瑞 华楠 【摘要】随着城市现代化发展&#xff0c;城市居住密度愈来愈大&#xff0c;城市建筑结构复杂多样化&#xff0c;高层建筑火灾发生率在不断地升高。对现代化城市面临的消防问题展开讨论&#xff0c;针对智慧消防在现代化城市建设中的现状进行了分析&#xff0c;并提…

python cv2.imread()和Image.open()的区别和联系

文章目录 1. cv2.imread()1.1 cv2.imread参数说明1.2 注意事项 2. Image.open()3. cv2.imread()与Image.open()相互转化3.1 cv2.imread()转成Image.open()&#xff1a;Image.fromarray()3.2 Image.open()转成cv2.imread()&#xff1a;np.array() 1. cv2.imread() cv2.imread()…

每日一题--删除链表的倒数第 N 个结点

破阵子-晏殊 燕子欲归时节&#xff0c;高楼昨夜西风。 求得人间成小会&#xff0c;试把金尊傍菊丛。歌长粉面红。 斜日更穿帘幕&#xff0c;微凉渐入梧桐。 多少襟情言不尽&#xff0c;写向蛮笺曲调中。此情千万重。 目录 题目描述&#xff1a; 思路分析&#xff1a; 方法及…

RK3568驱动指南|第八篇 设备树插件-第72章 设备树插件语法和编译实验

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

【Python百宝箱】Python轻松操控邮件:SMTP、POP3和IMAP的魅力

前言 在数字时代&#xff0c;电子邮件作为信息传递的主要手段&#xff0c;对个人和企业的日常工作至关重要。Python提供了多个强大的库&#xff0c;使得电子邮件的发送和接收变得轻松而灵活。本文将深入介绍Python中与电子邮件相关的主要库&#xff0c;为读者提供从基础到高级…

Diffusion Model: DDIM

本文相关内容只记录看论文过程中一些难点问题&#xff0c;内容间逻辑性不强&#xff0c;甚至有点混乱&#xff0c;因此只作为本人“备忘”&#xff0c;不建议其他人阅读。 DENOISING DIFFUSION IMPLICIT MODELS: https://arxiv.org/abs/2010.02502 前序知识 DDPM&#xff1a;…

零基础学python第一天||数和四则运算

数和四则运算 一提到计算机&#xff0c;当然现在更多人把她叫做电脑&#xff0c;这两个词都是指computer。不管什么&#xff0c;只要提到她&#xff0c;普遍都会想到她能够比较快地做加减乘除&#xff0c;甚至乘方开方等。乃至于&#xff0c;有的人在口语中区分不开计算机和计…

OSG粒子系统与阴影-雨效、雪效模拟(2)

雪效模拟示例 雪效模拟示例的代码如程序清单11-2所示&#xff1a; 1. /* 雪效模拟示例 */ 2. void snow_11_2(const string &strDataFolder) 3. { 4. osg::ref_ptr<osgViewer::Viewer> viewer new osgViewer::Viewer(); 5. osg::ref_ptr<osg::G…

如何学习VBA:3.2.8 OnTime方法与OnKey方法

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的劳动效率&#xff0c;而且可以提高数据处理的准确度。我推出的VBA系列教程共九套和一部VBA汉英手册&#xff0c;现在已经全部完成&#xff0c;希望大家利用、学习。 如果…

System-V共享内存和基于管道通信实现的进程池

文章目录 一.进程间通信:进程间通信的本质: 二.Linux管道通信匿名管道:关于管道通信的要点:基于匿名管道构建进程池: 三.System-V共享内存共享内存和命名管道协同通信 参考Linux内核源码版本------linux-2.4.3 一.进程间通信: 操作系统中,为了保证安全性,进程之间具有严格的独…

Jquery ajax 进行网络请求,同步阻塞引起的UI线程阻塞 (loading图片不显示 )

jax重新获取数据刷新页面功能&#xff0c;因为ajax属于耗时操作&#xff0c;想在获取数据且加载页面时显示加载遮罩层&#xff0c;结果发现了ajax的好多坑。 ajax 执行http网络请示时时&#xff0c;让遮罩层显示&#xff0c;ajax加载完毕后遮罩层消失。 因为我想让loadChart()…

卷积神经网络(CNN)识别验证码

文章目录 一、前言二、前期工作1. 设置GPU&#xff08;如果使用的是CPU可以忽略这步&#xff09;2. 导入数据3. 查看数据4.标签数字化 二、构建一个tf.data.Dataset1.预处理函数2.加载数据3.配置数据 三、搭建网络模型四、编译五、训练六、模型评估七、保存和加载模型八、预测 …

Ubuntu18.04安装A-Loam保姆级教程

系统环境&#xff1a;Ubuntu18.04.6 LTS 1.A-Loam的安装前要求&#xff1a; 1.1 ROS安装&#xff1a;参考我的另一篇博客 Ubuntu18.04安装ROS-melodic保姆级教程_灬杨三岁灬的博客-CSDN博客还是那句话&#xff0c;有时候加了这行也不好使&#xff0c;我是疯狂试了20次&#…

十六、互斥量

互斥量的目的就是为了实现互斥访问。 1、概述 (1)举例说明&#xff1a; 怎么独享厕所&#xff1f;自己开门上锁&#xff0c;完事了自己开锁。 你当然可以进去后&#xff0c;让别人帮你把门&#xff1a;但是&#xff0c;命运就掌握在别人手上了。 …

Task.Run为什么会存在内存泄漏的风险?

由于值类型是拷贝方式的赋值&#xff0c;捕获的本地变量和类成员是指向各自的值&#xff0c;对本地变量的捕获不会影响到整个类。但如果把类中的值类型改为引用类型&#xff0c;那这两者最终指向的是同一个对象值&#xff0c;这是否意味着使用本地变量还是无法避免内存泄漏&…

【java】-D参数使用

在开发过程中我们使用开源工具经常会用到在启动命令时候加入一个 -Dxxx 类型的参数。到底-Dxxx是干什么用的了。 官方文档 地址&#xff1a;文档地址 java命令使用 下面是来源于官方文档&#xff1a; java [options] classname [args] java [options] -jar filename [args…

FFmpeg零基础学习(二)——视频文件信息获取

目录 前言正文一、获取宽高信息1、核心代码2、AVFormatContext3、avformat_alloc_context4、avformat_open_input5、avformat_find_stream_info6、av_dump_format7、av_find_best_stream End、遇到的问题1、Qt Debug模式avformat_alloc_context 无法分配对象&#xff0c;而Rele…