【数据结构初阶】栈接口实现及经典OJ题超详解

news2025/1/12 16:03:48

文章目录

  • 1. 概念与结构
    • 1. 1 栈底层结构选型
  • 2. 栈实现
    • 2. 1 栈的定义
    • 2. 2 栈的初始化
    • 2. 3 入栈
    • 2. 4 判空
    • 2. 5 出栈
    • 2. 6 取栈顶元素
    • 2. 7 栈大小
    • 2. 8 栈销毁
    • 2. 9 打印
  • 3. 经典OJ题
    • 3. 1 有效的括号


1. 概念与结构

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

压栈:栈的插入操作叫做进栈/压栈/入栈入数据在栈顶
出栈:栈的删除操作叫做出栈。出数据也在栈顶

先进后出

1. 1 栈底层结构选型

栈的实现可以使用数组或者链表,但是相对而言数组的结构实现更优一些
因为栈是一个需要超高强度存取数据的数据结构,而数组尾插数据的代价比较小,比较合适。当然链表也是可以的。

2. 栈实现

2. 1 栈的定义

我们实现的栈应该是一个可以动态增长的栈,不然就会和静态顺序表一样会有许多的限制。
栈的底层是数组,那么也就是说这个数组应该是可以动态增长的,可以参考动态顺序表,我们需要一个capacity来存储数组的容量来判断需不需要扩容。
除此之外,我们应该怎么从栈中取出元素?那就需要把栈中有几个元素存储起来,但在这里,我们将其命名为top(注意top的值就是栈中存储元素的个数,不过我们将其理解为栈顶,其数值为栈中最后一个数据的上面一个位置的下标)。

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;		// 栈顶
	int capacity;	// 容量 
}Stack;

2. 2 栈的初始化

在最开始,我们需要将栈初始化,这里有2个步骤:

  1. a指向NULL
  2. topcapacity都置为0

这个初始化函数是在调用时先创建一个栈,再通过它的地址进行初始化。当然,也可以改成在函数内部动态开辟空间创建栈然后返回的形式,但要注意在销毁时应该将栈本身给free掉。

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

2. 3 入栈

void StackPush(Stack* ps, STDataType data);

在栈的最后面插入一个元素
有以下两个步骤:

  1. 判断容量是否足够,如果不够就扩容
  2. 对栈底层的顺序表进行尾插

在实现顺序表时,我们将检查容量这一步单独封装成了函数,因为这一步会被频繁调用,但在栈这里,只有入栈这一步需要用到检查容量,那就没有太大的必要单独封装了。
扩容时,和顺序表相似的,我们将容量扩大至原来的二倍,当然,也要注意容量为0的情况。

void StackPush(Stack* ps, STDataType data)
{
	assert(ps);
	//判断容量是否足够
	if (ps->capacity == ps->top)
	{
		//容量不够,扩容至2倍
		int newcapacity = 2 * ps->capacity;
		if (ps->capacity == 0)
			newcapacity = 2;
		STDataType* newa = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));
		if (!newa)
		{
			perror("realloc");
			exit(1);
		}
		ps->a = newa;
		ps->capacity = newcapacity;
	}
	//顺序表的尾插,top就是需要插入的位置的下标
	ps->a[ps->top++] = data;
}

2. 4 判空

int StackEmpty(Stack* ps);

判断栈中是否有元素直接判断top是否等于0并返回就可以了。
这个函数是为接下来的几个接口做准备。

int StackEmpty(Stack* ps)
{
	assert(ps);
	return ps->top == 0;
}

2. 5 出栈

void StackPop(Stack* ps);

出栈是从栈顶出栈,也就是删除栈顶元素,也只能从栈顶,对于栈来说,访问除栈顶之外的元素都是违法的
出栈就相当于顺序表的尾删,直接top--就可以了,但是在出栈之前要确保栈不为空

void StackPop(Stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));	//保证栈不为空
	ps->top--;	
}

2. 6 取栈顶元素

STDataType StackTop(Stack* ps);

直接将栈顶元素返回就可以了,注意top是栈顶的下一个元素的下标。
还要注意对栈进行判空,如果栈为空,那么这个函数就没有意义。

STDataType StackTop(Stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));
	return ps->a[ps->top - 1];
}

2. 7 栈大小

获取栈中数据个数,其实就是直接返回top的数值。

int StackSize(Stack* ps)
{
	assert(ps);
	return ps->top;
}

2. 8 栈销毁

void StackDestroy(Stack* ps);

栈中只有数组是通过动态内存管理得到的,只需要将其释放,再将其他的数据都置为0就可以了。

void StackDestroy(Stack* ps)
{
	assert(ps);
	free(ps->a);
	ps->capacity = 0;
	ps->top = 0;
}

注意:如果函数的创建是在初始化函数内部动态开辟空间创建栈然后返回的形式,应该传入二级指针,将ps本身给释放掉。

void StackDestroy(Stack** pps)
{
	assert(pps && *pps);	//这两个指针都需要解引用,所以都要判空
	free((*pps)->a);
	free(*pps);
}

其实通过这个函数我们就能知道为什么不采用动态开辟的方法创建数组了,正常来讲我们向其它函数传入的都是一级指针,但是如果是动态开辟栈的话就需要传入二级指针了,传入时不统一就会带来不方便。

2. 9 打印

事实上,对栈的直接遍历打印是违法的,因为栈不允许访问除栈顶元素之外的任何元素,所以也就无法遍历,那么自然也就无法打印了。
但是可以通过循环取栈顶元素,出栈这两个步骤来模拟打印

void StackPrint(Stack* ps)
{
	assert(ps);
	while (!StackEmpty(ps))
	{
		printf("%d ",StackTop(ps));
		StackPop(ps);
	}
}

当然,在打印之后,栈中就没有元素了。

3. 经典OJ题

3. 1 有效的括号

题目链接
1

bool isValid(char* s);

有效的括号是怎样的?

([)]是吗?显然不是,也就是说在这道题中,括号的左右两括号之间没有其他括号或者有完整的其他括号时,才能算是有效的括号

这时其实就可以用到栈这样的结构,如果是左括号就入栈,是右括号就比较栈顶是不是它对应的左括号并出栈,直到遍历结束之后,再判断一下栈是否为空就可以了。

参考代码:

//首先定义一个栈
typedef struct Stack
{
    char* data;
    int top;
    int capacity;
}Stack;

bool isValid(char* s) {
    Stack ST;
    //初始化
    ST.data=NULL;
    ST.top=ST.capacity=0;
    //遍历
    char* cur=s; 
    while(*cur)
    {
        if(*cur=='('||*cur=='['||*cur=='{')
        {
            //遇到左括号入栈
            if(ST.capacity==ST.top)
            {
                //扩容
                int newcapacity=2*ST.capacity;
                if(ST.capacity==0)
                    newcapacity=2;
                ST.data=(char*)realloc(ST.data,newcapacity*sizeof(char));
                ST.capacity=newcapacity;
            }
            ST.data[ST.top++]=*cur;
        }
        else
        {
            if(ST.top==0)	//如果遇到右括号时栈为空,那就是没有匹配的左括号
                return false;
            
            //出栈并匹配(穷举匹配)
            if(*cur==')'&&ST.data[ST.top-1]=='('||
               *cur==']'&&ST.data[ST.top-1]=='['||
               *cur=='}'&&ST.data[ST.top-1]=='{')
                ST.top--;
            else
                return false;
        }
        cur++;
    }
    //遍历完成后判空,看看有没有多余的左括号
    if(ST.top)
        return false;
    else
        return true;
}

当然,参考代码是在函数内部直接写出需要的栈接口,也可以把需要的栈接口先写到最前面,在这个函数内部直接调用
参考代码没有考虑栈的销毁,当然,为了严谨性,你可以想一下该怎么加上销毁。

栈这个结构的接口比较简单,其OJ题一般也是和其他的数据结构相结合的,所以放到后面的博客中。

谢谢你的阅读,喜欢的话来个点赞收藏评论关注吧!
我会持续更新更多优质文章

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

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

相关文章

IMS 注册流程(详细)

目录 业务模型 图1 EPC 网络附着示意图 图2 IMS 网络注册示意图 注册信令流程 图3 基本注册流程(EPC网络-融合HLR/HSS) IMS 注册流程 01:UE->P-CSCF 02:P-CSCF->I-CSCF 03:I-CSCF 处理 04:…

组成原理:体系结构,CPU,存储器,Cache

1,系统架构 1.1,组成结构 【硬件】是指计算机的实体部分,它由看得见摸得着的各种电子元件,各类光、电、机设备的实物组成。所有硬件通过总线和接口连接在一起,构成一台完整的计算机。 (1)运算器…

Spark的介绍

一、分布式的思想 不管是数据也好,计算也好,都没有最大的电脑,而是多个小电脑组合而成。 存储:将3T的文件拆分成若干个小文件,例如每500M一个小文件,将这些小文件存储在不同的机器上 。 -- HDFS 计算&#…

LeetCode_sql_day21(1440.计算布尔表达式的值)

描述: 表 Variables: ------------------------ | Column Name | Type | ------------------------ | name | varchar | | value | int | ------------------------ 在 SQL 中,name 是该表主键. 该表包含了存储的变量及其对应…

2024年华为9月4日秋招笔试真题题解

2024年华为0904秋招笔试真题 二叉树消消乐好友推荐系统维修工力扣上类似的题--K站中转内最便宜的航班 二叉树消消乐 题目描述 给定原始二叉树和参照二叉树(输入的二叉树均为满二叉树,二叉树节点的值范围为[1,1000],二叉树的深度不超过1000)&#xff0c…

智汇云舟斩获创客北京2024鲲鹏应用创新大赛北京区总决赛一等奖

近日,创客北京2024鲲鹏应用创新大赛华鲲振宇北京赛区总决赛在北京鲲鹏联合创新中心圆满举办。智汇云舟团队的参赛作品“视频孪生,把数字孪生升级为虚实共生”斩获鲲鹏原生开发赛道(泛政府)一等奖。 面向全球开发者的顶级赛事&…

python去除非页眉页脚,非背景非正式的图片、文字水印代码

import fitz import os import shutildef remove_watermarks_by_sizes(pdf_path, output_path, watermark_sizes, watermark_rects, watermark_texts):"""从PDF中删除特定大小的图片(水印)和特定的文字。参数:pdf_path (str): 输入PDF文件…

现金检测系统源码分享

现金检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vision …

草莓大模型(o1 )同步——实战2024国赛数学建模C题

模型介绍 这是一系列全新AI模型,能推理复杂的任务,解决比以前科学、编程、数学模型更难的问题。o1 模型(草莓)与 GPT-4o 的主要区别在于:它能够比前代更好地处理复杂的编程和数学问题,并能解释其推理过程.以往模型不同的是&#…

引用和指针的区别(面试概念性题型)

个人主页:Jason_from_China-CSDN博客 所属栏目:C系统性学习_Jason_from_China的博客-CSDN博客 概念概述 内存占用: 引用:引用一个变量时,实际上并不占用额外的内存空间,它就是原始变量的别名。指针&#xf…

裸金属 Ironic T和2024.1版本 功能比较

一、Train版 裸金属配置向导 1、系统环境 ansible 2.7.18 kolla-ansible 7.2.2.dev9[rootkolla-ansible-master ~]# python --version Python 2.7.5 [rootkolla-ansible-master ~]# cat /etc/centos-release CentOS Linux relea…

SAP B1 单据页面自定义 - 用户界面编辑字段

背景 接《SAP B1 基础实操 - 用户定义字段 (UDF)》,在设置完自定义字段后,如下图,通过打开【用户定义字段】可打开表单右侧的自定义字段页。然而再开打一页附加页面操作繁复,若是客户常用的定义字段,也可以把这些用户…

快充协议方案,Type-C接口受电端Sink取电快充协议芯片

快充协议芯片是确保充电器与设备之间兼容性的关键,它根据设备的需求提供合适的电压与电流,从 而实现更快速的充电体验。 快充协议芯片不仅仅是提升充电速度,更重要的是确保充电器与设备之间的兼容性,避免因协议不匹配导致的充电效…

从零开始打造一台简易计算机

从零开始打造一台可运行的简易计算机专题系列结合一个免费开源的 线上数字电路模拟器(仿真器), 从最基本的继电器(晶体管)功能讲起, 到最终完成一个可以批量执行指令的简易计算机. 跟随文中的步骤, 即可亲手在线上打造一台可运行的简易的计算机, 在此过程中, 将获得对计算机底…

2024lims实验室管理系统排名 6款LIMS软件厂商

随着实验室管理的不断升级,LIMS系统逐渐成为实验室不可或缺的一部分。这款实验室信息管理系统以其稳定性、多功能性和用户友好性在竞争激烈的市场中脱颖而出。 随着实验室管理的不断升级,LIMS系统逐渐成为实验室不可或缺的一部分。这款实验室信息管理系…

如何使用Python创建目录或文件路径列表

在 Python 中,创建目录或生成文件路径列表通常涉及使用 os、os.path 或 pathlib 模块。下面是一些常见的任务和方法,用于在 Python 中创建目录或获取文件路径列表。 问题背景 在初始阶段的 Python 学习过程中,可能遇到这样的问题&#xff1a…

NVG040W语音芯片:为制氧机带来个性化语音提示和报警功能

在当今社会,家庭医疗设备和健康保健产品越来越受到人们的关注。制氧机作为其中的一种,为许多需要氧气治疗的人们提供了重要的帮助。然而,对于许多用户来说,如何正确操作和维护这些设备仍然是一个挑战。为此,NVG040W语音…

点成分享 | 微生物浊度测量技术:比浊仪校准的最佳实践与策略

比浊仪通过检测悬浮液中微生物对光的散射程度来反映微生物含量。微生物浓度越高,透过的光越少,散射的光越多。因此,微生物浓度与透光度成反比,与吸光度成正比。该技术广泛应用于细菌浊度测定、抗生素药敏实验等微生物检测领域。 …

ElementPlus表单验证报错 formEl.validate is not a function

出现问题的代码 <!-- 密码重置弹框 --><el-dialog v-model"innerVisible" width"500" title"密码重置" append-to-body><el-form ref"ruleFormRef" style"max-width: 600px" :model"passForm" sta…

“鸿儒”——AIGC团队知识管理工作台

项目介绍 “鸿儒”——AIGC团队知识管理工作台是一项创新性的信息管理和协作平台&#xff0c;“鸿儒”立足于AIGC&#xff08;Artificial Intelligence Generated Content&#xff09;技术的前沿。该平台以机器学习和自然语言处理技术为核心&#xff0c;致力于协助团队更加高效…