数据结构入门:栈

目录

前言

1. 栈

1.1栈的概念及结构

 1.2 栈的实现

1.2.1 栈的定义

 1.2.2  栈的初始化

1.2.3 入栈

1.2.4 出栈

1.2.5  栈的元素个数

1.2.6 栈顶数据

1.2.7 栈的判空

 2.栈的应用

 2.1 题目一:括号匹配

2.1.1 思路

 2.1.2 分析

 2.1.3 题解

总结


前言

        无论你是计算机科学专业的学生、程序设计的爱好者,还是正在准备面试的求职者,本文将为你提供一份全面而深入的栈和队列指南。让我们一起探索栈和队列的双重魅力,为你的编程之路增添新的色彩。


1. 栈

1.1栈的概念及结构

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底

栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

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

 

 1.2 栈的实现

        栈的实现方法有两种,一种是顺序表的栈,另外一种就是链表实现的栈。相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小,所以这里我们使用顺序表来实现栈。

         如果熟练顺序表和链表操作,那栈就会相当轻松,栈的入栈出栈就相当于是尾插尾删,顺序表尾插尾删的效率高,这也是使用顺序表实现的原因。

1.2.1 栈的定义

首先我们需要先定义一个栈:

typedef int Datatype;
typedef struct Stack
{
	Datatype* a;
	int top;
	int capacity;
}Stack;

 栈中有栈顶(top),有栈的容量(size),还有存储的数据(a);

 1.2.2  栈的初始化

 

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

         这里对栈进行初始化时栈顶(top)可以置为-1,也可以置为0,置为0为了便于使用top作为数组下标插入数据。

1.2.3 入栈

        栈已经定义完成并且进行了初始化,接下来就是入栈操作。这里与顺序表的尾插略微有些不同。

void StackPush(Stack* ps, Datatype x)
{
	assert(ps);
	if (ps->top == ps->capacity)
	{
		int newcapacity = (ps->capacity == 0 ? 4 : ps->capacity * 2);
		Datatype* tmp = (Datatype*)realloc(ps->a, sizeof(Datatype) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
	ps->a[ps->top] = x;//top初始化为0,可以直接作为数组下标
	ps->top++;//入栈后top++,便于统计元素个数和下次入栈
}

        由于我们初始化时将栈的容量置为0,在这里我们在入栈操作时就需要进行开辟空间,但这里如果我们使用malloc开辟空间,就还需要进行扩容操作,所以我们直接使用realloc进行开辟空间。

 realloc在扩容时,如果原始区域空间为0,那么它的作用就类似于malloc。

         此外我们还需要有新开辟空间的大小,这里我们直接使用一个判断语句:newsize = (ps->size == 0 ? 4 : ps->size * 2);  如果size等于0就开辟4个存储数据的空间,如果不等于0就直接扩容为2倍。

1.2.4 出栈

 出栈操作就很简单了,也不需要销毁,直接进行top--:

void StackPop(Stack* ps)
{
	assert(ps);
	assert(ps->top > 0);
	ps->top--;
}

        但我们需要注意栈为空的情况,所有使用assert强制检查,如果为空直接报错终止程序,简单粗暴。

1.2.5  栈的元素个数

统计栈的元素个数接口也很简单,top就是栈中元素的个数

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

1.2.6 栈顶数据

Datatype TopData(Stack* ps)
{
	assert(ps);
	assert(ps->top > 0);

	return ps->a[ps->top - 1];
}

这个也非常简单,需要注意栈为空的情况。

1.2.7 栈的判空

bool IsEmpty(Stack* ps)
{
	assert(ps);
	return (ps->top == 0);
}

 2.栈的应用

         这些栈的基本操作我们已经实现了,接下来我们来实际应用一下。虽然栈的基本操作更为简单,但是栈在应用时数据的结构更加复杂,前边的顺序表和链表是栈和队列的基础。

 2.1 题目一:括号匹配

        这道题目我们可以使用数组实现并解决,但我们已经了解了栈,这道题目我们就使用顺序表栈来实现。我们可以直接复制上述栈基本操作的代码。将 typedef  int  Datatype;

 改为:typedef  char  Datatype;

题目描述:

 示例:

 题目链接:

有效括号

2.1.1 思路

         这道题目的思路很明确,入栈左括号,遇到匹配的右括号就出栈。如果最终栈为空就匹配成功。但匹配失败的情况有很多,接下来我们进行逐个分析。

 2.1.2 分析

         首先是入栈,如果为左括号就入栈,为右括号就匹配出栈。这里使用if…else语句更为简洁,入栈就需要我们调用入栈的函数接口。

        其次就是匹配、出栈。但在匹配之前我们还需要考虑特殊情况,就是如果没有出栈元素就直接匹配的情况,所以首先我们需要有一个判空操作,如果匹配时栈就为空就直接匹配失败,并销毁栈,这个属于左括号与右括号数量匹配失败。

         接着就是顺序匹配失败,这里就需要我们用到栈顶元素了,如果栈顶元素与匹配的括号不匹配就直接返回false,匹配失败,销毁栈。

        最后,匹配结束,存放括号数组为空,栈也为空就匹配成功。

 2.1.3 题解

匹配括号接口:

bool isValid(char* s) {
	Stack st;
	InItStack(&st);
	char top;
	while (*s)
	{
		if (*s == '(' || *s == '[' || *s == '{')
		{
			StackPush(&st, *s);
		}
		else
		{
			if(IsEmpty(&st))
			{
				DestoryStack(&st);
				return false;
			}
			top=TopData(&st);
			StackPop(&st);
			if((*s==']'&&top!='[')
			||(*s==')'&&top!='(')
			||(*s=='}'&&top!='{'))
            {
                DestoryStack(&st);
                return false;
            }
		}
        s++;
	}
	bool ret = IsEmpty(&st);
    DestoryStack(&st);
	return ret;
}

整体代码:

typedef char Datatype;
typedef struct Stack
{
	Datatype* a;
	int top;
	int size;
}Stack;

void InItStack(Stack* ps);

void DestoryStack(Stack* ps);

void StackPush(Stack* ps, Datatype x);

void StackPop(Stack* ps);

int Stacksize(Stack* ps);

Datatype TopData(Stack* ps);

bool IsEmpty(Stack* ps);

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

void DestoryStack(Stack* ps)
{
	assert(ps);
	ps->top = ps->size = 0;
	free(ps->a);
	ps->a = NULL;
}
void StackPush(Stack* ps, Datatype x)
{
	assert(ps);
	if (ps->top == ps->size)
	{
		int newsize = (ps->size == 0 ? 4 : ps->size * 2);
		Datatype* tmp = (Datatype*)realloc(ps->a, sizeof(Datatype) * newsize);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;
		ps->size = newsize;
	}
	ps->a[ps->top] = x;
	ps->top++;
}
void StackPop(Stack* ps)
{
	assert(ps);
	assert(ps->top > 0);
	ps->top--;
}
int Stacksize(Stack* ps)
{
	assert(ps);
	return ps->top;
}
Datatype TopData(Stack* ps)
{
	assert(ps);
	assert(ps->top > 0);

	return ps->a[ps->top - 1];
}
bool IsEmpty(Stack* ps)
{
	assert(ps);
	return (ps->top == 0);
}
bool isValid(char* s) {
	Stack st;
	InItStack(&st);
	char top;
	while (*s)
	{
		if (*s == '(' || *s == '[' || *s == '{')
		{
			StackPush(&st, *s);
		}
		else
		{
			if(IsEmpty(&st))
			{
				DestoryStack(&st);
				return false;
			}
			top=TopData(&st);
			StackPop(&st);
			if((*s==']'&&top!='[')
			||(*s==')'&&top!='(')
			||(*s=='}'&&top!='{'))
            {
                DestoryStack(&st);
                return false;
            }
		}
        s++;
	}
	bool ret = IsEmpty(&st);
    DestoryStack(&st);
	return ret;
}

         栈相对于链表和顺序表没有那么多的操作,更为简单,但在实际应用时数据结构更加复杂,但是别担心,后续学习C++后可以直接使用现成的库函数,不需要再对栈的各个操作进行实现。


  

总结

        栈是一种重要的数据结构,它以后进先出的方式操作数据。栈在递归算法、表达式求值、函数调用等场景中发挥着重要作用。通过学习栈,我们能够更好地理解数据结构的本质和算法的设计思想。栈不仅仅是一种数据存储的方式,更是一种思维方式和问题解决的工具。无论是计算机科学的学习者、程序设计的爱好者,还是正在准备面试的求职者,通过探索栈的原理和应用,我们能够提升自己的编程能力和解决问题的能力。让我们一起深入探索栈的魅力,为编程之路增添新的色彩。最后,感谢阅读!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从源码Debug深入spring事件机制,基于观察者模式仿写spring事件监听骨架

文章目录 1.测试案例2.DEBUG源码分析3. 异步监听4.ApplicationListener子接口5. 注解支持6. 基于观察者模式高仿spring事件监听6.1 先定义自定义一个事件6.2 定义两个监听器6.3 定义一个持有所有监听器的对象,类似spring的SimpleApplicationEventMulticaster6.4 事件…

【C++起飞之路】初级—— auto、范围for循环、宏函数和内联函数

auto、范围for、内联函数、宏函数和nullptr 一、auto — 类型推导的魔法(C 11)1、auto 是什么?2、工作原理3、优势4、限制和注意事项 二、范围for (C11)1、基本语法2、优势3、工作原理4、注意事项5、C11: 范围 for 循环的扩展: 三…

数据结构:力扣OJ题

目录 ​编辑题一:链表分割 思路一: 题二:相交链表 思路一: 题三:环形链表 思路一: 题四:链表的回文结构 思路一: 链表反转: 查找中间节点: 本人实力…

找不到资产文件project.assets.json

NuGet 在“obj”文件夹中写入名为 project.assets.json 的文件,.NET SDK 使用该文件来获取有关要传递到编译器的包的信息 。 如果在生成过程中找不到资产文件 project.assets.json,则会发生此错误。 1.执行命令的方式解决 点击工具,分别展开命…

【简单认识zookeeper+kafka分布式消息队列集群的部署】

文章目录 一、zookeeper1、定义2、工作机制3、Zookeeper 特点4、Zookeeper 数据结构5、Zookeeper 应用场景6、Zookeeper 选举机制(1)第一次启动选举机制(2)非第一次启动选举机制 7、部署zookeeper群集 二、消息队列概述1、为什么需…

释放AI创作潜能:从大模型训练到高产力应用

文章目录 每日一句正能量前言什么是人工智能生成内容(AIGC)人工智能生成内容(AIGC)能做什么为什么要用人工智能生成内容(AIGC)创作成果用Java实现冒泡排序算法学生信息收集系统学生请假管理系统需求分析教务…

kafka partition的数据文件(offffset,MessageSize,data)

partition中的每条Message包含了以下三个属性: offset,MessageSize,data,其中offset表示Message在这个partition中的偏移量,offset不是该Message在partition数据文件中的实际存储位置,而是逻辑上一个值&…

ApiPost的使用

1. 设计接口 请求参数的介绍 Query:相当于get请求,写的参数在地址栏中可以看到 Body: 相当于 post请求,请求参数不在地址栏中显示。 请求表单类型,用form-data json文件类型,用row 2. 预期响应期望 设置完每一项点一下生成响应…

9-数据结构-栈(C语言版)

数据结构-栈(C语言版) 目录 数据结构-栈(C语言版) 1.栈的基础知识 1.入栈,出栈的排列组合 情景二:Catalan函数(计算不同出栈的总数) 2.栈的基本操作 1.顺序存储 (1)顺序栈-定义…

Centos7.6 安装mysql过程全记录

在centos 7.6上 离线安装mysql 的步骤,可参考下文: 一、查看当前MySQL的安装情况并卸载 1. 查看当前MySQL的安装情况 查找之前是否安装了MySQL rpm -qa|grep -i mysql 2.卸载mysql 如果已经安装mysql,则需要先停止MySQL,再删除…

Redis集群 (三十九)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、Redis主从复制 1.1 概念 1.2 作用 1.3 缺点 1.4 流程 1.5 搭建 1.6 验证 二、Reids哨兵模式 2.1 概念 2.2 作用 2.3 缺点 2.4 结构 2.5 搭建 2.6 验证 三、Red…

基于 CentOS 7 构建 LVS-DR 群集 配置nginx负载均衡

环境配置: RHCE客户机192.168.100.146node1lvs192.168.100.145node2RS192.168.100.147node3RS192.168.100.148 配置ipvsadm httpd: [rootnode1 ~]# yum install ipvsadm.x86_64 [rootnode2 ~]# yum install http -y [rootnode2 ~]# systemctl …

SpringBoot案例-部门管理-修改

目录 前言 查看页面原型,明确需求 页面原型 需求 阅读接口文件 思路分析 功能接口开发 控制层(Controller类) 业务层(Service类) 业务类 业务实现类 持久层(Mapper类) 接口测试 前…

centos 7.x 单用户模式

最近碰到 centos 7.9 一些参数设置错误无法启动系统的情况,研究后可以使用单用户模式进入系统进行恢复操作。 进入启动界面,按 e ro 替换为 rw init/sysroot/bin/sh 替换前 替换后 Ctrl-x 进行重启进入单用户模式 执行 chroot /sysroot 可以查看日…

js jquery写一个画板 实现撤回、清空、换色的功能

画布的canvas画板的大小就是这个画板图片的大小 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><metaname"viewport&qu…

云计算|OpenStack|使用VMware安装华为云的R006版CNA和VRM---初步使用(二)

前言&#xff1a; 在前面一篇文章云计算|OpenStack|使用VMware安装华为云的R006版CNA和VRM---初始安装&#xff08;一&#xff09;_华为cna_晚风_END的博客-CSDN博客 介绍了基于VMware虚拟机里嵌套部署华为云的云计算&#xff0c;不过仅仅是做到了在VRM的web界面添加计算节点…

云安全攻防(八)之 Docker Remote API 未授权访问逃逸

Docker Remote API 未授权访问逃逸 基础知识 Docker Remote API 是一个取代远程命令行界面&#xff08;rcli&#xff09;的REST API&#xff0c;其默认绑定2375端口&#xff0c;如管理员对其配置不当可导致未授权访问漏洞。攻击者利用 docker client 或者 http 直接请求就可以…

Spring Boot集成Mybatis Plus通过Pagehelper实现分页查询

文章目录 0 简要说明Pagehelper1 搭建环境1.1 项目目录1.2 项目搭建需要的依赖1.3 配置分页插件拦截器1.4 源代码启动类实体类数据层xml映射文件业务层业务层实现类控制层接口配置swagger请求体 2 可能出现的疑问或者问题2.1 关于total属性疑问2.2 分页不生效问题 3 案例说明3.…

数据库技术--数据库引擎,数据访问接口及其关系详解(附加形象的比喻)

目录 背景数据库引擎Jet数据库&#xff1a;ISAM&#xff1a;ODBC&#xff08;Open Database Connectivity&#xff09;&#xff1a; 数据访问接口ADO&#xff08;ActiveX Data Objects&#xff09;DAO&#xff08;Data Access Objects&#xff09;RDO&#xff08;Remote Data O…

【C语言】操作符详解

目录 一、算数操作符 二、移位操作符 1.左移操作符 2.右移操作符 (1) 逻辑右移 (2) 算术右移 (3)小总结 三、位操作符 四、赋值操作符 五、单目操作符 六、关系操作符 七、逻辑操作符 八、 条件操作符 九、逗号表达式 十、下标引用、函数调用和结构成员 1. [ ]下…