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

news2024/7/4 3:26:27

🦄个人主页:修修修也

🎏所属专栏:数据结构

⚙️操作环境: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.coloradmin.cn/o/1251553.html

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

相关文章

基于Flutter的图片浏览器的实现

一 效果展示&#xff1a; 1. 图片展示&#xff1a; 2.混色&#xff0c;平铺&#xff0c;拉伸&#xff0c;原图展示 二 实验准备&#xff1a; 1.在包结构中创建images包来存放我们用到的图片&#xff0c;在pubspec.yaml中声明路径&#xff1a; 2. 检查虚拟机是否正常运行&…

【java】-D参数使用

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

初学vue3与ts:setup与setup()下的数据写法

把setup写在script里 <template><div><div class"index-title">script setup</div><div class"title">字符串&#xff1a;</div><div class"title-sub">ref版&#xff1a;{{strRef}}</div><…

【数据结构】树的概念以及二叉树

目录 1 树概念及结构 1.1 树的概念 1.3 树的存储 2 二叉树的概念及结构 2.1 概念 2.2 特殊的二叉树 2.3 二叉树的性质 2.4 二叉树的存储结构 1 树概念及结构 1.1 树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组…

原生实现底部弹窗效果 h5 小程序

<template><div class"home"><div class"btn" click"showPopupshow">弹出底部蒙层</div><div class"popup " catchtouchmove"true" :class"showPopup" ><div class"mask&q…

福州大学《嵌入式系统综合设计》实验六:图像加权融合

一、实验目的 掌握bmcv_image_add_weighted的使用 二、实验内容 搭建BMCV环境并成功运行加权融合例程 三、开发环境 开发主机&#xff1a;Ubuntu 22.04 LTS 硬件&#xff1a;算能SE5 本地如果有SE5硬件&#xff0c;则可以PC机作为客户端&#xff0c;SE5作为服务器端。本…

Kafka系列 - 生产者客户端架构以及3个重要参数

整体架构 整个生产者客户端由两个县城协调运行&#xff0c;这两个线程分别为主线程和Sender线程&#xff08;发送线程&#xff09;。 主线程中由KafkaProducer创建消息&#xff0c;然后通过可能的拦截器&#xff0c;序列化器和分区器之后缓存到消息累加器&#xff08;RecordAc…

歌手荆涛演唱的《春节回家》,一种情感的表达和文化的传承

歌手荆涛演唱的《春节回家》&#xff0c;一种情感的表达和文化的传承 春节回家&#xff0c;是中国传统文化中最为重要的传统节日之一&#xff0c;也是亿万华夏儿女最为期待的日子。每当春节临近&#xff0c;无论身在何处&#xff0c;人们都会收拾行囊&#xff0c;踏上归途&…

论文阅读_生成式Agent

英文名称: Generative Agents: Interactive Simulacra of Human Behavior 中文名称: 生成代理&#xff1a;**人类行为的交互式模拟** 文章: http://arxiv.org/abs/2304.03442 代码: https://github.com/joonspk-research/generative_agents 作者: Joon Sung Park 机构: 斯坦福大…

FireAlpacaforMac/win中文版—专业绘图软件释放你的创造力!

FireAlpaca是一款专业绘图软件&#xff0c;适用于Mac和Windows操作系统。无论你是初学者还是专业绘画师&#xff0c;FireAlpaca都能为你提供一个简单、强大的绘画平台&#xff0c;释放你的创造力。 首先&#xff0c;FireAlpaca拥有丰富的绘画工具和功能。它提供了各种绘画笔刷…

土壤多参数自动监测站实时守护农业的根基

WX-GSSQ10 随着科技的不断发展&#xff0c;农业领域也开始享受到技术进步带来的红利。其中&#xff0c;土壤多参数自动监测站的出现&#xff0c;为农业的精准管理和高效发展提供了强有力的支持。它像一位永不疲倦的哨兵&#xff0c;24小时全天候监测着土壤的状况&#xff0c;为…

LabVIEW当鼠标悬停在图形曲线上时显示坐标

LabVIEW当鼠标悬停在图形曲线上时显示坐标 在波形图上显示波形数据后&#xff0c;当鼠标放在波形图的曲线上时&#xff0c;如何自动显示对应点的坐标&#xff1f; 1. 创建事件结构&#xff0c;选择“波形图”作为“事件源”&#xff0c;选择“鼠标移动”作为“事件”&a…

深入解析:如何开发抖音票务小程序

当下&#xff0c;开发抖音票务小程序成为了吸引年轻用户群体的一种创新方式。本文将深入解析如何开发抖音票务小程序&#xff0c;探讨关键步骤和技术要点。 1.确定需求和功能 考虑到抖音的用户特点&#xff0c;可以加入与短视频相关的票务功能&#xff0c;如在线购票、观影记录…

中间件渗透测试-Server2131(解析+环境)

B-10&#xff1a;中间件渗透测试 需要环境的加qq 任务环境说明&#xff1a; 服务器场景&#xff1a;Server2131&#xff08;关闭链接&#xff09; 服务器场景操作系统&#xff1a;Linux Flag值格式&#xff1a;Flag&#xff5b;Xxxx123&#xff5d;&#xff0c;括…

【后端卷前端】

为啥现在对后端要求这么高?为啥不要求前端会后端呢? 可能是后端人太多了,要求后端需要会前端的框架(vue react angular ), 这不我为了适应市场的需求来系统的学习vue了: 生成一个基础的vue项目 创建vue项目 vue create projectname 创建vitevue npm init vitelatest p…

STM32 启动文件分析

STM32 启动文件分析 基于STM32F103VET6芯片的 startup_stm32f10x_hd.s 启动文件分析 设置栈&#xff0c;将栈的大小Stack_Size设置为0x00004900&#xff08;18688/102418KB&#xff09;&#xff0c;即局部变量不能大于18KB。&#xff08;EQU等值指令&#xff0c;将0x0000490…

「Verilog学习笔记」数据累加输出

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 在data_out准备好&#xff0c;valid_b拉高时&#xff0c;如果下游的ready_b为低&#xff0c;表示下游此时不能接收本模块的数据&#xff0c;那么&#xff0c;将会拉低ready…

UWB实时定位系统源码,历史活动轨迹显示,视频联动,电子围栏

UWB实时定位系统源码&#xff0c;工厂企业人员安全定位&#xff0c;UWB源码 行业背景 工业企业多存在很多有毒有害、高危高压等生产环境&#xff0c;带电设备众多&#xff0c;容易发生安全事故&#xff1b;人员只能凭记忆遵守各项生产安全规范&#xff0c;如某些危险区域范围、…

OpenCV简介及安装

前言 因为最近想做图像处理、人脸检测/识别之类的相关开发&#xff0c;所以就开始补OpenCV的相关知识&#xff0c;便开个专栏用于记录学习历程和在学习过程中遇到的一些值得注意的重点和坑。 学习过程基本上也是面向官方文档和Google。 简介 OpenCV(开源的计算机视觉库)是基于…

Python编程之魂之运算符的优先级教程

文章目录 前言优先级概述相同优先级结合性运算符优先级一览表运算符优先级重点说明结语关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例③Python小游戏源码五、面试资…