c语言实现栈

news2025/1/11 0:15:41

文章目录

  • 前言
  • 一、栈的特征
  • 二、栈的实现
    • 1、栈的设计
    • 2、栈的初始化和销毁
    • 3、元素的入栈和出栈
    • 4、返回栈顶元素
  • 三、栈的应用


前言

在学习完链表之后,接下来就要了解另外的两个常用的线性数据结构,栈和队列。

一、栈的特征

:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。==栈中的数据元素遵守后进先出LIFO(Last In First Out)==的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
在这里插入图片描述

出栈:栈的删除操作叫做出栈。出数据也在栈顶。
在这里插入图片描述

二、栈的实现

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。

1、栈的设计

我们可以直接使用一个定长数组来设计栈,然后每次插入和删除数据都在数组的末尾进行尾插和尾删。该设计和顺序表中的静态顺序表的设计一致,就是栈只允许在栈顶进行元素的删除和插入。

#define N 10
typedef int STDataType;
typedef struct Stack
{
	STDataType a[N];
	int top;  //栈顶
}ST;

但是使用定长数组设计时,如果进入栈的数据太多还需要扩容,进入栈的数据太少时又浪费空间,所以还可以使用和动态顺序表一致的设计,即使用动态开辟的数组。

typedef int STDataType;
typedef struct Stack
{
	STDataType* data;
	int top;  //栈顶
	int capacity;  //用来记录动态数组的大小,当栈满时再开辟空间。
}ST;

2、栈的初始化和销毁

栈的初始化就是将创建的ST结构体中用来存数据的动态数组的指针先置为NULL,避免其为野指针,将动态数组的大小capacity置为0。然后将top先置为0或-1。
当将top置为0时,当要入栈时,就先将数组中下标为top的元素中放入数据,然后top再++,此时下标为top-1的元素就为栈顶元素,top表示了栈中的元素。
在这里插入图片描述
当将top置为-1时,当有元素要入栈时,就需要先将top++,然后再将数组中下标为top的元素中放入数据。因为top为-1时指向的是栈底的下面,需要先将top++,然后才能在栈底放入第一个元素。此时top指向的就是栈顶元素,当要返回栈顶元素时直接将数组中下标为top的元素返回即可,但是要计算栈是否为空时,就需要判断top==-1。
在这里插入图片描述
下面实现栈的操作是按照top刚开始设为0而实现的。即真正的栈顶是top下面的那个元素,此时top指向的元素数据为空。所以当返回栈顶元素时,需要将下标为top-1的元素返回。top的值刚好就是栈中元素的值,所以判断栈空时就用top==0来判断。
在这里插入图片描述

栈的初始化。

void StackInit(ST* ps)
{
	assert(ps);
	ps->data = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

栈的销毁就是将动态申请的数组的内存释放。

void StackDestory(ST* ps)
{
	assert(ps);
	//将动态数组申请的空间都释放。
	free(ps->data);
	ps->data = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

3、元素的入栈和出栈

元素入栈就相当于在数组的尾部插入元素。但是元素在入栈前要判断一下此时栈是否满了,输入满了就需要再将栈扩容。

void StackPush(ST* ps, STDataType x)
{
	assert(ps);
	//当栈的容量不够时
	if (ps->top == ps->capacity)
	{
		//当动态数组的大小为0时,就申请4个空间;当动态数组大小不为0时,就说明栈满了,需要扩容。
		int newCapacity = (ps->capacity == 0) ? 4 : (ps->capacity * 2);
		//给动态数组申请空间,用来存放数据
		STDataType* tmp = (STDataType*)realloc(ps->data, sizeof(STDataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->data = tmp;
		ps->capacity = newCapacity;
	}
	//将数据存到数组的末尾,然后栈顶向后移。
	ps->data[ps->top] = x;
	ps->top++;
}

元素出栈就相当于将数组末尾的数据删除,但是在出栈前要判断此时栈是否为空,如果为空就没有元素可以出栈。
判断栈空的函数。

bool StackEmpty(ST* ps)
{
	assert(ps);
	/*if (ps->top <= 0)
	{
		return true;
	}
	else
	{
		return false;
	}*/

	return ps->top == 0;
}

出栈的函数。

void StackPop(ST* ps)
{
	assert(ps);
	//出栈时要检查栈中有没有元素,有元素才可以出栈,没有元素就不可以出栈
	assert(!StackEmpty(ps));
	ps->top--;
}

4、返回栈顶元素

返回栈顶元素就是将此时栈顶的元素返回,因为此时top指向的是下一个要存数据的位置,此位置当前还没有数据,所以当返回栈顶元素时,实际返回的是数组下标为top-1的元素的值。

STDataType StackTop(ST* ps)
{
	assert(ps);
	//出栈时要检查栈中有没有元素,有元素才可以出栈,没有元素就不可以出栈
	assert(!StackEmpty(ps));
	return ps->data[(ps->top)-1];
}

三、栈的应用

经过上面的介绍我们发现栈的实现与顺序表的实现类似,差别就是栈只允许在末尾进行插入和删除。那么栈这个数据结构怎么应用呢?我们可以通过一个经典题来体会栈的特点。
题目
在这里插入图片描述
题目链接

题目分析
该问题就可以使用栈来解决,遍历字符串,当遇到左括号 ( [ { 时,就将这些左括号进行压栈,当遇到右括号 ) ] }时,就取出栈顶元素来与当前括号相匹配,如果两个括号类型一致就将该左括号出栈,并且访问字符串的下一个括号。如果两个括号匹配不一致,则返回false。当匹配到字符串末尾时,此时栈也为空,说明这些左括号和右括号都匹配,此时返回true。
代码
这个题中用到了我们上面写的一些栈的操作,需要将这些对应的函数都放到代码里面,这样提交时才不会报错。


#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
//静态数组实现栈
//#define N 10
//typedef int STDataType;
//typedef struct Stack
//{
//	STDataType a[N];
//	int top;
//}ST;

//动态数组实现栈
typedef char STDataType;
typedef struct Stack
{
	STDataType* data;
	int top;
	int capacity;
}ST;

//栈的初始化
void StackInit(ST* ps);

//检查栈空
bool StackEmpty(ST* ps);

//栈的销毁
void StackDestory(ST* ps);

//元素入栈
void StackPush(ST* ps, STDataType x);

//元素出栈
void StackPop(ST* ps);

//返回栈顶元素
STDataType StackTop(ST* ps);

void StackInit(ST* ps)
{
	assert(ps);
	ps->data = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

bool StackEmpty(ST* ps)
{
	assert(ps);
	/*if (ps->top <= 0)
	{
		return true;
	}
	else
	{
		return false;
	}*/

	return ps->top == 0;
}

void StackDestory(ST* ps)
{
	assert(ps);
	//将动态数组申请的空间都释放。
	free(ps->data);
	ps->data = NULL;
	ps->top = 0;
	ps->capacity = 0;
}


void StackPush(ST* ps, STDataType x)
{
	assert(ps);
	//当栈的容量不够时
	if (ps->top == ps->capacity)
	{
		//当动态数组的大小为0时,就申请4个空间;当动态数组大小不为0时,就说明栈满了,需要扩容。
		int newCapacity = (ps->capacity == 0) ? 4 : (ps->capacity * 2);
		//给动态数组申请空间,用来存放数据
		STDataType* tmp = (STDataType*)realloc(ps->data, sizeof(STDataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->data = tmp;
		ps->capacity = newCapacity;
	}
	//将数据存到数组的末尾,然后栈顶向后移。
	ps->data[ps->top] = x;
	ps->top++;
}

void StackPop(ST* ps)
{
	assert(ps);
	//出栈时要检查栈中有没有元素,有元素才可以出栈,没有元素就不可以出栈
	assert(!StackEmpty(ps));
	ps->top--;
}

STDataType StackTop(ST* ps)
{
	assert(ps);
	//出栈时要检查栈中有没有元素,有元素才可以出栈,没有元素就不可以出栈
	assert(!StackEmpty(ps));
	return ps->data[(ps->top)-1];
}

bool isValid(char * s){
    ST st; 
		//创建一个栈并且初始化。
    StackInit(&st);

		//遍历括号字符串
    while(*s!='\0')
    {
			//当为左括号时,就进行压栈
        if((*s=='(') || (*s=='[') || (*s=='{'))
        {
            StackPush(&st,*s);
            s++;
        }
        else
        {
					//如果为右括号,并且此时栈已空,就说明括号不匹配,
						if(StackEmpty(&st))
            {
								StackDestory(&st);
                return false;
            }
						//取出栈顶元素
            char top = StackTop(&st);
						//并且将栈顶元素进行出栈
            StackPop(&st);  
						//如果两个括号匹配就访问下一个字符
            if((top=='(' && *s==')') || (top=='[' && *s==']') || (top=='{' && *s=='}'))
            {
                s++;
            }
            else
            {
							//如果两个括号不匹配就返回false
							StackDestory(&st);
                return false;
            }
        }
    }

		//如果字符串访问完后,此时栈中还有左括号,说明括号不匹配
    if(!StackEmpty(&st))
    {
			StackDestory(&st);
        return false;
    }
		StackDestory(&st);
		//当字符串访问完,且此时栈为空,说明括号都匹配,
    return true;
}

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

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

相关文章

斩获多家名校邀请函|检验医师终赴多伦多大学访学深造

M医生学术背景不错&#xff0c;具备较扎实的基础医学理论及较熟练的实验技能&#xff0c;也有一定的英语能力&#xff0c;但因本身不够自信&#xff0c;担心申请不到名校通不过CSC审批。我们先后为其获得新加坡科技研究局&#xff08;A*Star&#xff09;、加拿大麦吉尔大学、多…

为什么企业需要IT服务管理?

什么是IT服务管理? 将IT服务管理功能扩展到技术服务之外&#xff0c;解决以业务为中心通过单一平台&#xff0c;门户和服务目录管理服务供需&#xff0c;通过PaaS/低代码开发工具加速创新和工作流自动化。 为什么企业需要IT服务管理&#xff1f; 为了更好管理公司内不同业务&a…

功能强大、超低功耗的STM32WL55JCI7、STM32WL55CCU7、STM32WL55CCU6 32位无线远距离MCU

STM32WL55xx 32位无线远距离MCU嵌入了功能强大、超低功耗、符合LPWAN标准的无线电解决方案&#xff0c;可提供LoRa、(G)FSK、(G)MSK和BPSK等各种调制。STM32WL55xx无线MCU的功耗超低&#xff0c;基于高性能Arm Cortex-M4 32位RISC内核&#xff08;工作频率高达48MHz&#xff09…

优化ADC 采样计算的简单思路

想法是尽量简化ADC 采样值换算到真实电压的过程&#xff0c;最好是不涉及浮点运算&#xff0c;整数乘除法成本比较低。 原理 对于使用了分压电阻采样输入电压的情形&#xff0c;电路大概是这样&#xff1a; 分压比例为&#xff1a; K R 1 R 2 R 1 (1) K \frac{R1 R2}{R1}…

java 实现N次多项式回归

使用的类库 org.apache.commons.math3 maven <dependency><groupId>org.apache.commons</groupId><artifactId>commons-math3</artifactId><version>3.6.1</version> </dependency> 推荐工具 如果只是做学术研究用&…

摩托车外廓尺寸检测软件

本系统为摩托车外廓尺寸检测软件&#xff0c;该系统共涉及两种测量方法&#xff1a;自动测量和手动测量&#xff0c;旨在测量出每一台摩托车的外廓尺寸&#xff0c;包括但不限于摩托车的车长、车宽、车高、轮距、前悬、后悬、前伸距等需要测量的参数&#xff0c;可通过运行软件…

ATFX汇市:美元指数强势状态延续,市价逼近104关口

环球汇市行情摘要—— 昨日&#xff0c;美元指数上涨0.27%&#xff0c;收盘在103.61点&#xff0c; 欧元贬值0.48%&#xff0c;收盘价1.0846点&#xff1b; 日元贬值0.24%&#xff0c;收盘价145.87点&#xff1b; 英镑贬值0.19%&#xff0c;收盘价1.2733点&#xff1b; 瑞…

Vulnhub: bassamCTF: 1靶机

kali&#xff1a;192.168.111.111 靶机&#xff1a;192.168.111.210 信息收集 端口扫描 nmap -A -sC -v -sV -T5 -p- --scripthttp-enum 192.168.111.210 修改hosts文件 爆破出子域名welcome wfuzz -H HOST: FUZZ.bassam.ctf -u http://192.168.111.210 -w /usr/share/wor…

GB28181视频监控国标平台EasyGBS角色绑定设备通道的功能优化

GB28181视频监控国标平台EasyGBS是基于国标GB28181协议、支持多路设备同时接入的视频监控/视频云服务平台&#xff0c;支持对多平台、多终端分发RTSP、RTMP、FLV、HLS、WebRTC等格式的视频流。国标GB28181平台EasyGBS可提供视频直播监控、云端录像、云存储、检索回放、智能告警…

电子器件系列47:稳压二极管

C80857_稳压二极管_BZX84C15LT1G_规格书_ONSEMI(安森美)稳压二极管规格书 232-稳压二极管的串联使用&#xff0c;和普通二极管串联也能灵活稳压_哔哩哔哩_bilibili 基本释义    稳压二极管&#xff0c;英文名称Zener diode&#xff0c;又叫齐纳二极管。    利用pn结反向击穿…

IPv6 基础概念

IPv6 基础概念 组播地址 IPv6的组播与IPv4相同&#xff0c;用来标识一组接口&#xff0c;一般这些接口属于不同的节点。一个节点可能属于0到多个组播组。发往组播地址的报文被组播地址标识的所有接口接收。例如组播地址FF02::1表示链路本地范围的所有节点&#xff0c;组播地址…

什么是3D智慧档案馆?智慧档案馆如何建设?

档案馆3D可视化解决方案 一、引言 随着科技的飞速发展和数字化转型的推进&#xff0c;档案馆作为文化遗产和重要信息的保管者&#xff0c;面临着新的挑战和机遇。为了更好地保护和管理档案资料&#xff0c;提高档案馆的管理效率和透明度&#xff0c;我们提出了一种档案馆3D可视…

代驾系统:革新出行体验的智能伙伴

在现代社会&#xff0c;出行方式正在经历着一场革命&#xff0c;而代驾系统正是这场革命中的一位智能伙伴。通过结合智能科技和出行需求&#xff0c;代驾系统为我们带来了便捷、安全、个性化的出行体验。本文将介绍代驾系统的工作原理&#xff0c;并通过Python代码演示其基本功…

ChatGLM-Med,HuaTuo,ChatDoctor

ChatGLM-Med&#xff1a;基于中文医学知识的ChatGLM模型微调 HuaTuo&#xff1a;基于中文医学知识的LLaMA微调模型 ChatDoctor&#xff1a;基于常见医疗数据微调的LLaMA 目录 ChatGLM-MedHuaTuoChatDoctor ChatGLM-Med 模型为ChatGLM-6B&#xff0c;微调数据集为&#xff1a;医…

uniapp使用uni.chooseLocation()打开地图选择位置

使用uni.chooseLocation()打开地址选择位置&#xff1a; 在Uniapp源码视图进行设置 添加这个属性&#xff1a;"requiredPrivateInfos":["chooseLocation"] ​ </template><view class"location_box"><view class"locatio…

repair taillights

自己修理汽车尾灯&#xff0c;可以根据型号去某宝买个回来自己安装&#xff1a;

【前端从0开始】JavaSript——js基础语法

1. JS基础语法 1.1. JS概念 JavaScript 是用于实现用户交互、动态控制文档的外观和内容, 动态控制浏览器操作、创建cookies等网页行为的跨平台、跨浏览器的由浏览器解释执行的客户端脚本语言。 js文档 1.2. 特点 是基于对象的弱类型语言 弱类型语言: 某一个变量被定义类型…

HDLBits-Verilog学习记录 | Verilog Language-Vectors(1)

文章目录 11.vectors | vector012.vectors in more detail | vector113.Vector part select | Vector214.Bitwise operators | Vectorgates15.Four-input gates | Gates416.Vector concatenation operator | Vector317.Vector reversal 1 | Vectorr18. Replication operator | …

石油和天然气行业如何实现数字化转型和工业4.0

石油和天然气行业的数字化转型正面临着前所未有的挑战和机遇。尽管过去相对滞后&#xff0c;这个复杂而庞大的行业正逐渐意识到数字化的紧迫性&#xff0c;以应对市场变化、降低运营成本、提高效率和确保可持续性。然而&#xff0c;数字化转型的进程并非一帆风顺&#xff0c;行…

字节跳动基于DataLeap的DataOps实践

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 本文根据 ArchSummit 全球架构师峰会&#xff08;深圳站&#xff09;来自抖音数据研发负责人王洋的现场分享实录整理而成&#xff08;有删减&#xff09;&#xff0…