栈的实现和括号匹配问题

news2024/9/21 20:29:45

1.什么是栈

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

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶

出栈:栈的删除操作叫做出栈。出数据也在栈顶

后进先出 

2.栈的实现

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


第一步:创建一个头文件和两个源文件

在头文件中进行结构定义和函数声明

#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;//栈顶
	int capacity;//容量
}ST;

//初始化和销毁
void STInit(ST* pst);
void STDestroy(ST* pst);

//入栈 出栈
void STPush(ST* pst, STDataType x);
void STPop(ST* pst);

//取栈顶数据
STDataType STTop(ST* pst);

//判空
bool STEmpty(ST* pst);

//获取数据个数
int STSize(ST* pst);

第二步:栈的函数实现

初始化

void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
	//top指向栈顶数据的下一个位置
	pst->top = 0;
	//top指向栈顶数据
	//pst->top = -1;
	pst->capacity = 0;
}

注意:top等于-1的时候top指向栈顶,top等于0的时候top指向栈顶的下一个位置,大家可以根据自己的情况选择。


销毁

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

传过来的地址不能为NULL如果为空我们就不能对他进行解引用,所以断言一下


入栈

void STPush(ST* pst, STDataType x)
{
	assert(pst);
	//扩容
	if (pst->top == pst->capacity)
	{
		int newcapcity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, newcapcity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		pst->a = tmp;
		pst->capacity = newcapcity;
	}
	pst->a[pst->top] = x;
	pst->top++;
}

初始化的时候我们并没有开辟空间,所以我们需要先申请空间,先开辟4个空间不够再扩容,我们把开辟好的空间用一个临时变量保存起来然后对他进行判断,避免我们空间申请失败导致原地址丢失,然后更改空间容量大小,最后入数据


出栈

void STPop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	pst->top--;
}

竟然要出数据那么肯定要有数据才能出,所以断言一下,我们直接top--就可以了


取栈顶数据

STDataType STTop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	return pst->a[pst->top - 1];
}

我们要有数据才能取数据所以加个断言,直接返回top-1的下标就是栈顶的数据


判空

bool STEmpty(ST* pst)
{
	assert(pst);
	return pst->top == 0;
}

top为0栈就为空


获取数据个数

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

top表示下标,也就是元素个数


最后一步:测试test.c

int main()
{
	ST s;
	STInit(&s);
	STPush(&s, 1);
	STPush(&s, 2);
	printf("%d\n", STTop(&s));

	STPush(&s, 3);
	STPush(&s, 4);
	while (!STEmpty(&s))
	{
		printf("%d\n", STTop(&s));
		STPop(&s);
	}
	STDestroy(&s);
	return 0;
}

注意:出栈可以边入边出,入栈1 2 3 4,出栈不一定是4 3 2 1


3.括号匹配问题

OJ链接:有效的括号

左括号必须和右括号相匹配必须是成对出现的,如果匹配就返回true否则返回false,这道题乍一看不好判断,其实我们可以用栈来解决,栈是后进先出的原则,如果是左括号就入栈,如果是右括号就出栈顶的左括号进行判断是否匹配,此时的栈里面都是左括号,这里我们的需求是后进先出,我们要让右括号和后进的左括号相匹配,这不就完美的匹配了后进先出。

因为C语言没有自带的栈所以我们需要把写好的栈放进去,C++会有自带的栈。

代码如下:

bool isValid(char* s) {

    ST st;
    STInit(&st);
    while(*s)
    {
        //左括号入栈
        if(*s == '(' || *s == '[' || *s == '{')
        {
            STPush(&st,*s);
        }
        //右括号取栈顶左括号尝试匹配
        else
        {
            if(STEmpty(&st))
            {
                STDestroy(&st);
                return false;
            }
            char top = STTop(&st);
            STPop(&st);
            //不匹配
            if((top == '(' && *s !=')')
            || (top == '[' && *s !=']')
            || (top == '{' && *s !='}'))
            {
                STDestroy(&st);
                return false;
            }
        }
        ++s;
    }
    //栈不为空,说明左括号比右括号多,数量不匹配
    bool ret = STEmpty(&st);
    STDestroy(&st);
    return ret;
}

全部代码如下:

typedef char STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

//初始化和销毁
void STInit(ST* pst);
void STDestroy(ST* pst);

//入栈 出栈
void STPush(ST* pst, STDataType x);
void STPop(ST* pst);

//取栈顶数据
STDataType STTop(ST* pst);

//判空
bool STEmpty(ST* pst);

//获取数据个数
int STSize(ST* pst);

//初始化和销毁
void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
	//top指向栈顶数据的下一个位置
	pst->top = 0;
	//top指向栈顶数据
	//pst->top = -1;
	pst->capacity = 0;
}
void STDestroy(ST* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->top = pst->capacity = 0;
}

//入栈 出栈
void STPush(ST* pst, STDataType x)
{
	assert(pst);
	//扩容
	if (pst->top == pst->capacity)
	{
		int newcapcity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, newcapcity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		pst->a = tmp;
		pst->capacity = newcapcity;
	}
	pst->a[pst->top] = x;
	pst->top++;
}
void STPop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	pst->top--;
}

//取栈顶数据
STDataType STTop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	return pst->a[pst->top - 1];
}

//判空
bool STEmpty(ST* pst)
{
	assert(pst);
	return pst->top == 0;
}

//获取数据个数
int STSize(ST* pst)
{
	assert(pst);
	return pst->top;
}

bool isValid(char* s) {

    ST st;
    STInit(&st);
    while(*s)
    {
        //左括号入栈
        if(*s == '(' || *s == '[' || *s == '{')
        {
            STPush(&st,*s);
        }
        //右括号取栈顶左括号尝试匹配
        else
        {
            if(STEmpty(&st))
            {
                STDestroy(&st);
                return false;
            }
            char top = STTop(&st);
            STPop(&st);
            //不匹配
            if((top == '(' && *s !=')')
            || (top == '[' && *s !=']')
            || (top == '{' && *s !='}'))
            {
                STDestroy(&st);
                return false;
            }
        }
        ++s;
    }
    //栈不为空,说明左括号比右括号多,数量不匹配
    bool ret = STEmpty(&st);
    STDestroy(&st);
    return ret;
}

 总结

栈是一种特殊的线性数据结构,它遵循后进先出(Last In, First Out,LIFO)的原则。栈的主要操作包括在栈顶插入元素(称为压栈,push)和从栈顶移除元素(称为弹栈,pop)。由于这种操作限制,栈在访问和操作元素时表现出一种特殊的顺序性。

栈的主要特点包括:

  • 1.后进先出(LIFO):栈中的数据元素按照它们进入栈的顺序的逆序进行排列。最后进入栈的元素将最先被移除,而最先进入栈的元素将最后被移除。
  • 2.操作受限:栈只允许在栈顶进行插入和移除操作。这种限制确保了栈的后进先出特性。
  • 3.应用广泛:栈在计算机科学和软件工程中有广泛的应用。它们常用于实现函数调用(函数调用栈)、表达式求值(算术表达式的括号匹配和计算顺序)、内存分配(如自动变量存储)等。栈还被用作一种数据结构和算法设计的辅助工具,例如在深度优先搜索(DFS)中,栈被用来保存待访问的节点。

栈的实现方式有多种,包括基于数组的静态栈和基于链表的动态栈等。这些实现方式各有优缺点,具体选择取决于应用场景和性能需求。在实际应用中,栈的使用通常需要与其他数据结构和算法相结合,以实现复杂的程序逻辑和功能。

栈的一个重要特性是它可以很容易地通过数组或链表来实现,并且具有常数时间的插入和删除操作(在栈顶)。这使得栈成为一种高效且灵活的数据结构,适用于需要按照特定顺序处理元素的情况。

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

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

相关文章

数据中心智能化运维发展研究报告(2023)解读

数据中心智能化运维发展研究报告&#xff08;2023&#xff09;解读 《数据中心智能化运维发展研究报告&#xff08;2023&#xff09;》探讨了数据中心智能化运维的概念、核心内容、实际应用和发展建议。报告指出&#xff0c;通过人工智能、大数据等新一代信息技术的深度应用&a…

【recast-navigation-js】使用three.js辅助绘制Agent寻路路径

目录 说在前面setAgentTarget绘制寻路路径结果问题其他 说在前面 操作系统&#xff1a;windows 11浏览器&#xff1a;edge版本 124.0.2478.97recast-navigation-js版本&#xff1a;0.29.0golang版本&#xff1a;1.21.5上一篇&#xff1a;【recast-navigation-js】使用three.js辅…

STM32CubeIDE使用过程记录

最近在做一款机器人的开发&#xff0c;使用到了STM32CubeIDE&#xff0c;这里记录一些使用技巧方便后续查阅。 STM32CubeIDE使用过程记录 快捷键开启代码自动补全功能看门狗设置CRC设置IO口取反定时器设置 及 定时器中断外部中断GPIO配置STC15单片机GPIO模式配置片内闪存&#…

PyTorch学习7:加载数据集

文章目录 前言一、epoch&#xff0c;batch-size和iteration二、示例1.说明2.代码示例 总结 前言 介绍PyTorch中加载数据集的相关操作。Dataset和DataLoader 一、epoch&#xff0c;batch-size和iteration epoch&#xff1a;所有训练数据完成一次前馈和反馈 batch-size&#x…

深度学习革命-AI发展详解

深度学习革命 《深度学习革命》是一部引人深思的作品&#xff0c;详细讲述了深度学习技术的发展历程及其对各个行业的深远影响。由杰出的计算机科学家、深度学习专家撰写&#xff0c;这本书不仅适合科技领域的专业人士阅读&#xff0c;也为普通读者提供了一个理解人工智能革命…

Vue TypeScript 实战:掌握静态类型编程

title: Vue TypeScript 实战&#xff1a;掌握静态类型编程 date: 2024/6/10 updated: 2024/6/10 excerpt: 这篇文章介绍了如何在TypeScript环境下为Vue.js应用搭建项目结构&#xff0c;包括初始化配置、创建Vue组件、实现状态管理利用Vuex、配置路由以及性能优化的方法&#x…

【电机控制】FOC算法验证步骤——电流环PI参数、速度环PI参数

【电机控制】FOC算法验证步骤——电流环PI参数、速度环PI参数 文章目录 前言一、电流环PI1.TI手册 二、速度环PI1.TI手册——根据稳定性和带宽计算速度环PI参数2.TI手册——根据稳定性和带宽计算速度环PI参数 三、参考文献总结 前言 【电机控制】直流有刷电机、无刷电机汇总—…

Python私教张大鹏 Vue3整合Vue Router之编程式导航

除了使用 <router-link> 创建 a 标签来定义导航链接&#xff0c;我们还可以借助 router 的实例方法&#xff0c;通过编写代码来实现。 导航到不同的位置 注意: 下面的示例中的 router 指代路由器实例。在组件内部&#xff0c;你可以使用 $router 属性访问路由&#xff…

vue-cli是什么?和 webpack是什么关系?

前言 Vue CLI是Vue.js项目的官方脚手架&#xff0c;基于Node.js与Webpack构建。安装Vue CLI前需确保Node.js已安装&#xff0c;随后通过npm全局安装。Vue CLI能迅速创建和管理Vue.js项目&#xff0c;提升开发效率。而Webpack则负责资源打包&#xff0c;通过配置文件管理依赖、插…

FiRa标准UWB MAC实现(三)——距离如何获得?

继续前期FiRa MAC相关介绍,将FiRa UWB MAC层相关细节进一步进行剖析,介绍了UWB技术中最重要的一个点,高精度的距离是怎么获得的,具体使用的测距方法都有哪些,原理又是什么。为后续FiRa UWB MAC的实现进行铺垫。 3、测距方法 3.1 SS-TWR SS-TWR为Single-Sided Two-Way Ra…

通过python操作redis(windows)

注意在连接之前要确保 redis 服务已经安装。 更多的安装信息请查看&#xff1a;https://blog.csdn.net/sinat_20471177/article/details/132042779?spm1001.2014.3001.5501 redis 模块 Python 要使用 redis&#xff0c;需要先安装 redis 模块。如果要做数据导入/导出操作的…

动手学深度学习4.10 实战Kaggle比赛:预测房价-笔记练习(PyTorch)

以下内容为结合李沐老师的课程和教材补充的学习笔记&#xff0c;以及对课后练习的一些思考&#xff0c;自留回顾&#xff0c;也供同学之人交流参考。 本节课程地址&#xff1a;实战 Kaggle 比赛&#xff1a;预测房价_哔哩哔哩_bilibili 本节教材地址&#xff1a;4.10. 实战Ka…

公式转换坑

在线LaTeX公式编辑器-编辑器 (latexlive.com) 这个好用 latex输入后转mathtype等 1 \mathcal{V}\{0,1,\ldots,|\mathcal{V}|-1\} 这个玩意在Word死活打不出来 使用下面的方法也不行 mathtype也不行 故换符号之 LaTeX公式与MathType公式如何快速转换-MathType中文网 如何在…

.Net实现SCrypt Hash加密

方案1 &#xff08;加密后存储“算法设置”、“盐(随机值)”、“Hash值”&#xff0c;以“$”分隔&#xff09;&#xff1a; //Nuget引入SCrypt.NET库 using Org.BouncyCastle.Crypto.Generators; using Scrypt; using System; using System.Security.Cryptography; namespace …

Python基础教程(九):装饰器

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; &#x1f49d;&#x1f49…

强大的.NET的word模版引擎NVeloDocx

在Javer的世界里&#xff0c;存在了一些看起来还不错的模版引擎&#xff0c;比如poi-tl看起来就很不错&#xff0c;但是那是人家Javer们专属的&#xff0c;与我们.Neter关系不大。.NET的世界里Word模版引擎完全是一个空白。 很多人不得不采用使用Word XML结合其他的模版引擎来…

怎样快速获取Vmware VCP 证书,线上考试,voucher报名优惠

之前考一个VCP证书&#xff0c;要花大一万的费用&#xff0c;可贵了&#xff0c;考试费不贵&#xff0c;贵就贵在培训费&#xff0c;要拿到证书&#xff0c;必须交培训费&#xff0c;即使vmware你玩的很溜&#xff0c;不需要再培训了&#xff0c;但是一笔贵到肉疼的培训费你得拿…

嵌入式Linux系统编程 — 3.4 access、chmod和 umask函数修改文件访问权限

目录 1 文件访问权限 1.1 文件权限基本概念 1.2 普通权限 1.3 特殊权限 2 目录权限 3 access函数检查文件权限 3.1 access函数简介 3.2 示例程序 3.3 chmod修改文件权限 3.4 fchmod函数 4 umask 函数 4.1 umask简介 4.2 示例程序 1 文件访问权限 1.1 文件权限基本…

奇安信停服,国内还有什么可用的高防么?

这里写自定义目录标题 背景DDOS怎么办&#xff1f;方案推荐总结 背景 继前段时间百度云加速通知免费服务&#xff0c;6月底奇安信也将停止服务&#xff0c;到时候国内将几乎不存在免费好用的高防CDN了&#xff1b;类似的事情还有阿里云和腾讯云的一年期免费SSl证书也都停止供应…

2024 AEE | 风丘科技将亮相日本爱知国际会展中心——共同创造!

2024年名古屋汽车工程博览会&#xff08;Automotive Engineering Exposition 2024 NAGOYA&#xff09;将于7月17-19日在日本爱知县国际展示场&#xff08;Aichi Sky Expo&#xff09;开展。本展会是专门为活跃在汽车行业的工程师和研究人员举办的汽车技术展览&#xff0c;汇聚了…