栈(从数据结构的三要素出发)

news2024/11/24 4:48:22

文章目录

  • 逻辑结构
  • 物理结构
    • 顺序栈
    • 链栈
    • 共享栈
  • 数据的操作
    • 顺序栈的基本操作
    • 链栈的基本操作
    • 共享栈的基本操作
  • 数据结构的应用
    • 栈在括号匹配中的应用
    • 栈在表达式求值中的应用
    • 栈在递归调用中的应用

逻辑结构

栈是只允许在一端进行插入或删除操作的线性表。首先栈是一种线性表,但限定这种线性表只能在某一端进行插入和删除操作。

栈的数学性质:当 n n n个不同的元素进栈时,出栈元素的不同排列个数为 1 n + 1 C 2 n n \frac{1}{n+1}C_{2n}^n n+11C2nn(卡特兰公式)。

在这里插入图片描述


物理结构

顺序栈

利用静态数组实现,并需要记录栈顶指针,且栈的大小不可改变

typedef struct {
	int data[Maxsize];		// 定义栈中元素
	int top;				// 定义栈顶指针
} SqStack;

链栈

利用链表实现,只需要记录头指针,利用链表的头插法实现进栈操作,解决了顺序栈中栈的大小不可扩充的问题。
在这里插入图片描述

typedef struct LinkNode {
	int data;					// 数据域
	struct LinkNode *next;		// 指针域
} LinkNode, *LiStack;

共享栈

利用栈底位置的相对不变性,可以让两个顺序栈共享一个一维数组,将两个栈的栈底分别设置在共享空间的两端,两个栈的栈顶向共享空间的中间延伸,解决了顺序栈空间利用率不足的问题。

在这里插入图片描述

typedef struct {
	int data[Maxsize];		// 数据域
	int top1, top 2;		// 两个栈顶指针
} SStack;

数据的操作

顺序栈的基本操作

初始化

void InitStack(SqStack &s)
{	
	s.top = -1;
}

判断栈为空

bool isEmpty(SqStack s)
{	
	if (s.top == -1) return true;
	return false;
} 

判断栈为满

bool isFull(SqStack s)
{	
	if (s.top == Maxsize - 1) return true;
	return false;
}

入栈

bool Push(SqStack &s, int x)
{	
	if (!isFull(s)) 
	{
		s.data[ ++ s.top] = x;
		return true;
	}
	return false;
}

出栈

bool Pop(SqStack &s, int &x)
{	
	if (!isEmpty(s)) 
	{
		x = s.data[s.top -- ];
		return true;
	}
	return false;
}

读取栈顶元素

bool GetTop(SqStack s, int &x)
{	
	if (!isEmpty(s)) 
	{
		x = s.data[s.top];
		return true;
	}
	return false;
}

链栈的基本操作

初始化

void InitStack(LiStack s)
{	
	s->next = NULL;
}

判断栈为空

bool isEmpty(LiStack s)
{	
	if (s->next == NULL) return true;
	return false;
} 

入栈

bool Push(LiStack s, int x)
{	
	LinkNode *t = (LinkNode *) malloc (sizeof(LinkNode));
	t->next = s->next;
	s->next = t;
	return true;
}

出栈

bool Pop(SqStack s, int &x)
{	
	if (!isEmpty(s)) 
	{
		LinkNode *t = s->next;
		x = t->data;
		s->next = t->next;
		free(t);
		return true;
	}
	return false;
}

读取栈顶元素

bool GetTop(SqStack s, int &x)
{	
	if (!isEmpty(s)) 
	{
		x = s->next->data;
		return true;
	}
	return false;
}

共享栈的基本操作

初始化

void InitStack(SStack &s)
{	
	s.top1 = -1;
	s.top2 = Maxsize;
}

判断栈为空(true:判断栈1,false:判断栈2)

bool isEmpty(SStack s, bool flag)
{	
	if (s.top1 == -1 && flag) return true;
	else if (s.top2 == Maxsize && !flag) return true;
	return false;
} 

判断栈为满

bool isFull(SStack s)
{	
	if (s.top1 + 1 == s.top2) return true;
	return false;
}

入栈(true:入栈1,false:入栈2)

bool Push(SStack &s, int x, bool flag)
{	
	if (!isFull(s)) 
	{
		if (flag) s.data[ ++ top1] = x;
		else s.data[ -- top2] = x;
		return true;
	}
	return false;
}

出栈(true:出栈1,false:出栈2)

bool Pop(SStack &s, int &x, bool flag)
{	
	if (!isEmpty(s, flag)) 
	{
		if (flag) x = s.data[top -- ];
		else x = s.data[top ++ ];
		return true;
	}
	return false;
}

读取栈顶元素(true:读栈1,false:读栈2)

bool GetTop(SStack s, int &x)
{	
	if (!isEmpty(s, flag)) 
	{
		if (flag) x = s.data[top];
		else x = s.data[top];
		return true;
	}
	return false;
}

数据结构的应用

栈在括号匹配中的应用

在这里插入图片描述

bool bracketCheck(char str[], int length)
{
	SqStack s, InitStack(s);
	
	for (int i = 0; i < length; i ++ )
	{
		if (str[i] == '(' || str[i] == '[' || str[i] == '{')		// 遇到左括号进栈
			Push(s, str[i]);
		else 
		{
			if (isEmpty(s)) return false;		// 若遇到右括号,但栈是空的,证明左括号多了一个,则匹配不成功
			
			char topElem;
			Pop(s, topElem);

			/*左右括号不匹配*/
			if (str[i] == ')' && topElem != '(') return false;
			if (str[i] == ']' && topElem != '[') return false;
			if (str[i] == '}' && topElem != '{') return false;
		}
	}
	return isEmpty(s);		// 左右括号全部匹配
}

栈在表达式求值中的应用

在这里插入图片描述
在这里插入图片描述

  • 栈中运算符的优先级高于当前运算符的优先级时:可以得出基于栈顶元素的运算就可以被确定了。
  • 栈中运算符的优先级等于当前运算符的优先级时:基于左优先原则(左侧先做运算)。

其实就是中缀表达式转后缀表达式的过程中,边转换边计算(一旦确定运算就直接计算,再计算完的操作数压回栈中)就可以实现表达式的求值。

计算单元

void eval(Stack<int> &num, Stack<char> &op)
{
	int x = num.top();
	num.pop();
	int y = num.top();
	num.pop();
	char c = op.top();
	op.pop();

	if (c == '+')
        num.push(x + y);
    else if (c == '-')
        num.push(y - x);
    else if (c == '*')
        num.push(x * y);
    else 
        num.push(y / x);
}

计算表达式单元

int exEval(char str[], int length)
{
	unordered_map<char, int> pr = {{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};			// 定义运算符的优先级
	Stack<int> num;
	Stack<char> op;
	
`	for (int i = 0; i < length; i ++ )
	{
		if (isdigit(str[i]))
		{
			int x = 0;
			while (i < length && isdigit(str[i])) x = x * 10 + (str[i] - '0'), i ++ ;		// 将字符类型转换成数字
			num.push(x);
			i -- ;
		}
		else if (str[i] == '(') op.push(str[i]);
		else if (str[i] == ')')
		{
			while (op.top() != '(') eval(num, op);		// 将括号内的所有表达式已确定,直接计算
			op.pop();
		}
		else			// 操作符的情况 
		{
			while (op.size() && op.top() != '(' && pr[op.top()] >= pr[str[i]]) eval(num, op);			// 将已确定的运算式计算
			op.push(str[i]);		// 将待定运算符入栈
		}
	}
	while (op.size()) eval();		// 若栈内还有元素,直接做计算
	return num.top();				// 栈顶元素就是最终计算的结果
}

栈在递归调用中的应用

在这里插入图片描述
在这里插入图片描述
以斐波那契数列为例,其定义为:

F ( n ) = { F ( n − 1 ) + F ( n − 2 ) , n > 1 1 , n = 1 0 , n = 0 F(n)= \begin{cases}F(n-1)+F(n-2), & n>1 \\ 1, & n=1 \\ 0, & n=0\end{cases} F(n)= F(n1)+F(n2),1,0,n>1n=1n=0

int F(int n)
{	
	if (n == 0) return 0;
	if (n == 1) return 1;
	return F(n - 1) + F(n - 2);
}

递归调用需满足以下两个条件:

  • 递归表达式(递归体)
  • 边界问题(递归出口)

精髓:能否将原始问题转换成属性相同但规模较小的子问题。

以F(5)为例,以下是递归调用的执行过程:
在这里插入图片描述

其中F(3)被调用2次,F(2)被调用3次,F(1)被调用5次,F(0)被调用3次,故递归调用效率低下,但是代码实现简单,容易理解。

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

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

相关文章

数据结构-队列(带图详解)

目录 队列的概念 画图理解队列 代码图理解 代码展示(注意这个队列是单链表的结构实现) Queue.h(队列结构) Queue.c(函数/API实现) main.c(测试文件) 队列的概念 队列&#xff08;Queue&#xff09;是一种基础的数据结构&#xff0c;它遵循先进先出&#xff08;First In …

本地部署Whisper实现语言转文字

文章目录 本地部署Whisper实现语言转文字1.前置条件2.安装chocolatey3.安装ffmpeg4.安装whisper5.测试用例6.命令行用法7.本地硬件受限&#xff0c;借用hugging face资源进行转译 本地部署Whisper实现语言转文字 1.前置条件 环境windows10 64位 2.安装chocolatey 安装chocol…

无人机+飞行服务:无人机飞防服务(打药+施肥+播种)技术详解

无人机飞防服务&#xff0c;结合了先进的无人机技术与农业实践&#xff0c;为现代农业提供了高效、精准的打药、施肥和播种解决方案。以下是对这些技术的详细解析&#xff1a; 一、无人机打药技术 无人机打药技术利用无人机搭载喷雾设备&#xff0c;对农田进行精准施药。通过…

修改vuetify3的开关组件v-switch在inset模式下的大小

<v-switchv-model"model":label"Switch: ${model.toString()}"hide-detailsinset></v-switch><style lang"scss" scoped> .custom-switch {:deep(.v-switch__thumb) {height: 18px !important; /* 设置开关按钮的高度 */width…

编一个自己的万年历

编一个自己的万年历 前阶段突然想查一下某一天是星期几&#xff0c;于是自己编了一个[小程序][https://blog.csdn.net/weixin_41905135/article/details/138972055?spm1001.2014.3001.5501]&#xff0c;但是功能很单一&#xff0c;就是单纯的查是星期几。&#xff08;虽然用网…

解决深度确定问题:使用不相交集合森林

解决深度确定问题&#xff1a;使用不相交集合森林 引言不相交集合森林&#xff08;DSF&#xff09;基础按秩合并与路径压缩深度确定问题的解决方案实现MAKE-TREE修改FIND-SET实现FIND-DEPTH实现GRAFT分析最坏情况运行时间结论参考文献 引言 在计算机科学中&#xff0c;树结构是…

多维数据库创建

多维数据库 小白的数据仓库学习笔记 2024/5/21 上午 文章目录 多维数据库Cube的作用&#xff1a;什么是多维数据库维的级别多维数据分析方法如何构建多维数据集&#xff1f;创建项目创建数据源创建数据源视图创建多维数据集维度表中缺失的值拖拽过去建立维度结构设计类型启动连…

现代C++ 如何使用 Lambda 使代码更具表现力、更容易理解?

使用 Lambda 使代码更具表现力 一、Lambda VS. 仿函数二、总结 一、Lambda VS. 仿函数 Lambda 是 C11 中最引人注目的语言特性之一。它是一个强大的工具&#xff0c;但必须正确使用才能使代码更具表现力&#xff0c;而不是更难理解。 首先&#xff0c;要明确的是&#xff0c;…

【LeetCode】【5】最长回文子串

文章目录 [toc]题目描述样例输入输出与解释样例1样例2 提示Python实现动态规划 个人主页&#xff1a;丷从心 系列专栏&#xff1a;LeetCode 刷题指南&#xff1a;LeetCode刷题指南 题目描述 给一个字符串s&#xff0c;找到s中最长的回文子串 样例输入输出与解释 样例1 输入…

2024电工杯数学建模B题Python代码+结果表数据教学

2024电工杯B题保姆级分析完整思路代码数据教学 B题题目&#xff1a;大学生平衡膳食食谱的优化设计及评价 以下仅展示部分&#xff0c;完整版看文末的文章 import pandas as pd df1 pd.read_excel(附件1&#xff1a;1名男大学生的一日食谱.xlsx) df1# 获取所有工作表名称 e…

派可数据助力制造企业数字化生产管理新能力提升

生产管理是现代企业运营的核心之一&#xff0c;它决定了产品的质量、生产效率和企业的竞争力。在一个日益竞争激烈、市场需求多变的商业环境中&#xff0c;如何高效地组织和管理生产过程成为了企业不容忽视的重要课题。 过去&#xff0c;生产管理可能主要侧重于物理工厂的运作…

Sping源码(八)—registerBeanPostProcessors

序言 之前我们用大量的篇幅介绍过invokeBeanFactoryPostProcessors()方法的执行流程。 而invokeBeanFactoryPostProcessors的主要逻辑就是遍历执行实现了BeanDefinitionRegistryPostProcesso类(主要是针对BeanDefinition的操作)和BeanFactoryPostProcessor(主要针对BeanFacrot…

【C语言】深入理解指针(一)(上)

本篇文章将讲解&#xff1a; &#xff08;1&#xff09;内存和地址 &#xff08;2&#xff09;指针变量和细致 &#xff08;3&#xff09;指针变量类型的意义 一&#xff1a;内存和地址 &#xff08;1&#xff09;内存 在讲内存和地址之前&#xff0c;我们讲一个生活中的…

混合组网VS传统网络:智能硬件混合组网优劣势浅要解析

智能硬件混合组网是一种利用多种通信技术相结合的方法&#xff0c;以实现更灵活、更可靠的网络连接。通过蓝牙、Wi-Fi、LoRa、4G相互之间的不同通讯方式&#xff0c;根据应用场景的不同以及现场实际环境&#xff0c;优选最佳物联网混合组网方案&#xff0c;以达到部署最便捷性价…

618知识狂欢,挑本好书,点亮智慧生活!

618精选编程书单&#xff1a;提升你的代码力 一年一度的618又到啦&#xff01;今年的618就不要乱买啦&#xff0c;衣服买多了会被淘汰&#xff0c;电子产品买多了会过时&#xff0c;零食买多了会增肥&#xff0c;最后怎么看都不划算。可是如果你购买知识&#xff0c;坚持阅读&a…

2024年了, 你还不会使用node.js做压力测试?

前些天刷抖音&#xff0c;看到网传的Java继父&#xff0c;求人攻击压测他的网站&#xff0c;这不得摩拳擦掌。 所以今天来聊聊如何对自己的项目、接口进行压力测试。 压力测试的目的 首先, 绝对不是为了压测、攻击别人的网站为乐。 1、探索线上系统流量承载的极限&#xff…

鲁教版六年级数学下册-笔记

文章目录 第五章 基本平面图形1 线段、射线、直线2 比较线段的长短3 角4 角的比较5 多边形和圆的初步认识第六章 整式的乘除1 同底数幂的乘法2 幂的乘方与积的乘方3 同底数幂的除法4 零指数幂与负整数指数幂5 整式的乘法6 平方差公式7 完全平方公式8 整式的除法 第七章 相交线与…

保障餐饮场所安全:定期送检可燃气体报警器

在餐饮行业&#xff0c;火灾隐患一直备受关注。餐厅、茶饮店等场所常常使用燃气设备&#xff0c;而这些设备带来了潜在的安全隐患。 为了及时发现并预防可燃气体泄漏&#xff0c;可燃气体报警器的定期送检显得尤为重要。那么&#xff0c;为什么可燃气体报警器需要定期送检呢&a…

20.有序性与内存屏障

文章目录 有序性与内存屏障1.重排序1.1.编译器重排序1.2.CPU重排序1.2.1.指令级重排序1.2.2.内存系统重排序1.3.As-if-Serial规则 2.内存屏障2.1.硬件层面的内存屏障2.1.2.写屏障2.1.3.读屏障2.1.4.全屏障 2.2.硬件层的内存屏障作用2.3.案例 有序性与内存屏障 有序性 与 可见性…

基于英飞凌BGT60LTR11AIP E6327芯片具低功耗的脉冲多普勒操作模式常用于汽车应用的雷达上

芯片特征&#xff1a; 60 GHz收发器MMIC&#xff0c;带一个发射器和一个接收器单元封装天线&#xff08;AIP&#xff09;&#xff08;6.73.30.56 mm3)低功耗的脉冲多普勒操作模式自主模式用于运动和运动方向的集成检测器运动检测信号的直接输出目标检测范围的15个可配置阈值检测…