学习C/C++语言系列(2)栈

c++栈详解 在算法的优化中,有一种经常使用的技巧就是单调性(递增或递减)的运用。比如要保证栈的元素是单调递增的,当要进入的元素比栈顶元素小时,就要弹出栈顶元素或者丢掉这个元素不进入栈。从第1天开始用直线连接后面的某些天的股价,希望连线是递增的,并且所有股价不会超过这些直线。l push操作:向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;l pop操作:从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。例如有任务:增长折线。 阅读详情

栈是什么

        栈是一种特殊的线性表,特殊在哪呢?特殊在于栈上的空间只能后进先出,即最后进来的只能最先出去。这就好比硬币管里的硬币,只能先拿出最后放出去的。

这种后进先出的原则就叫做Last In First Out(LIFO)。

栈的C语言实现

栈的实现既可以用数组实现,也可以用单链表来实现。相对来讲,数组的实现更优,因为数组在尾部插入数据并不需要遍历,而且数组因为是连续存放缘故,缓存命中率更高。

栈的具体实现

先来简单思考一下,我们的栈要实现哪些基本功能。1.希望能把栈上的元素给我打印出来(测试用)。2.希望能有初始化一个栈的函数。3.希望能有一个入栈的函数。4.希望有一个出栈的函数。5.给出栈顶元素的函数。6.给出栈中有效元素个数的函数。7.判断栈是否为空的函数。8.销毁栈的函数。

这些其实和顺序表是很像的,唯一不同的就是栈只能后进先出。

栈的定义

        为方便后续修改存储的数据类型,将int进行改名。

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

初始化栈

        这里我倾向于在初始化的时候给个初始空间,这样在后续入栈上就不需要去判断是否没有空间。

// 初始化栈
void StackInit(Stack* ps)
{
	assert(ps);
	STDataType* tmp = (STDataType*)malloc(sizeof(STDataType) * 2);
	if (tmp == NULL)
	{
		printf("Malloc Fail In StackInit\n!");
		exit(-1);
	}
	ps->a = tmp;
	ps->top = -1;// top为栈顶元素的下标
	ps->capacity = 2;
}

入栈

        入栈也是很简单的,需要注意的是要判断栈的空间是不是满了。

// 入栈
void StackPush(Stack* ps, STDataType data)
{
	assert(ps && ps->a);
	if (ps->top == ps->capacity - 1)
	{
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * (ps->capacity) * 2);
		if (tmp == NULL)
		{
			printf("Realloc Fail In StackPush!\n");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity *= 2;//初始化给了初始空间后 这里就不需要判断capacity是否为0
	}
	(ps->a)[++(ps->top)] = data;
}

出栈

        出栈更简单,因为不需要去干什么操作,top--即可。top记录的是有效数据,只要不有效,管他是什么值都没用,top就是它的顶。

// 出栈
void StackPop(Stack* ps)
{
	assert(ps && ps->a);
	if (ps->top == -1)
		return;
	//不需要free 可以直接覆盖
	(ps->top)--;
}

获取栈顶元素

// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
	assert(ps && ps->a);
	assert(ps->top != -1);
	return (ps->a)[ps->top];
}

检测和显示函数

// 获取栈中有效元素个数
int StackSize(Stack* ps)
{
	assert(ps && ps->a);
	return ps->top + 1;
}

// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps)
{
	assert(ps && ps->a);
	return ps->top == -1 ? 1 : 0;
}

// 销毁栈
void StackDestroy(Stack* ps)
{
	assert(ps && ps->a);
	free(ps->a);
	ps->a = NULL;
}

// 显示栈中元素
void StackPrint(Stack* ps)
{
	assert(ps && ps->a);
	if (ps->top == -1)
	{
		printf("Nothing!\n");
		return;
	}
	for (int i = 0; i <= ps->top; i++)
		printf("%d ", ps->a[i]);
	printf("\n");
}

最后

        最后呢,我们来测试一下栈有没有出错的地方,测试一下。

void test()
{
	Stack st;
	StackInit(&st);
	StackPush(&st, 1);
	StackPush(&st, 2);
	StackPush(&st, 3);
	StackPush(&st, 4);
	StackPush(&st, 5);
	StackPush(&st, 6);
	StackPrint(&st);
	StackPop(&st);
	StackPrint(&st);
	StackPop(&st);
	StackPrint(&st);
	StackPop(&st);
	StackPrint(&st);
	StackPop(&st);
	StackPrint(&st);
	printf("%d\n", StackEmpty(&st));

	StackPop(&st);
	StackPop(&st);

	printf("%d\n", StackEmpty(&st));
	StackDestroy(&st);
	StackInit(&st);

	printf("%d\n", StackEmpty(&st));

}


int main()
{
	test();
	return 0;
}

 

ok,没用什么严重错误,都跑起来了。但是有了顺序表为啥还要有栈呢,我们来看下面这道题目。

用栈解决有效括号检测匹配问题

这是一道leetcode上面的题目:力扣

 思路

        其实我们随便写一个带括号的式子来观察一下。如:(((()))())。当然我这里这里只有小括号,其他的括号也是一样的。

        我们可以发现一个规律,那就是一个右边是右括号的左括号,两个一定相等。如果我们重复的不停的消除这一对对括号,最后将不剩下括号,符合这样的要求的表达式,它的括号分布一定是有效的。

        这段话可能有点绕,看下图。

 

我们不停地从头开始碰到一个右边是右括号的左括号则将二者一起消除。最后,如果这个式子的括号分布是有效的,将会得到空,换言之如果最后找不到符合条件的左括号,但式子中仍有括号,则不有效。

那么,如何用栈去解决这个问题呢?

我们可以这样,如果是一个左括号,我们把这个左括号放到栈上去,然后继续遍历,如果是右括号,那么就让这个右括号前的左括号出栈。由于栈只能后进先出,所以这个出的一定是这个右括号前一个左括号,然后继续遍历,重复这样的操作。这是不是相当于上面讲到的绑定消除呢?进行到最后,怎么判断是否有效呢?如果此时栈中没用左括号了,那说明左括号都被消除了,可以说明是有效的。这种判断能判对大部分情况,但是有一种情况例外,那就是只有右括号。所以我们在碰到右括号的时候要判断一下,栈中有没有左括号,如果没有左括号,但是却喷到个右括号,所以肯定不行。

代码实现

由于,C没有栈的库,所以必须要自己实现一个栈。

在这里呢,我用的栈函数都是上面用到的函数,这里只给出关键函数。而且注意,STDataType要改成char。

bool isValid(char* s)
{
	Stack st;
	StackInit(&st);
	while (*s != '\0')
	{
		if (*s == ')' || *s == ']' || *s == '}')
		{
			if (StackEmpty(&st))
				return false;
			else
			{
				if ((*s == ')' && StackTop(&st) != '(')
					|| (*s == ']' && StackTop(&st) != '[')
					|| (*s == '}' && StackTop(&st) != '{')
					)
					return false;
				else
					StackPop(&st);
			}
		}
		else
			StackPush(&st, *s);
		s++;
	}
	if (StackEmpty(&st))
		return true;
	return false;
}

番外

其实我在之前有根据这个原理做出了一个加减乘除表达式计算器,括号可以随便给,程序会边进行计算,边判断括号是否有效,思路其实就是上面讲到的思路。只不过那个使用python写的,我看如果得空,我就把它弄成C语言的,并进行一些优化,然后写一篇博客。

C++栈(stack)详解 C++栈详解 阅读详情

相关推荐

用栈解决N皇后问题(超详细注释、C/C++实现)

用栈解决N皇后问题(超详细注释、C/C++实现) 目的: 深入掌握栈应用的算法设计 内容: 编写一个程序,求解n皇后问题,即在n*n方格棋盘上放置n个皇后,要求每个皇后不同行、不同列、不同左右对角线 皇后个数n由用户输入,其值不能超过20,输出所有的解 采用类似于栈求解迷宫问题的方法 GitHub地址(包含.cpp文件和可执行程序exe) N皇后问题 -by- GitHub 源代码(经VS...

JunsIr的技术栈 6034

数据结构——栈(C++ 实现)

使用C++实现栈的功能

weixin_74753331的博客 4224

[C/C++] 函数调用的栈分配

         当调用(call)一个函数时,主调函数将声明中的参数表以逆序压栈,然后将当前的代码执行指针(eip)压栈,跳转到被调函数的入口点。        进入被调函数时,函数将esp减去相应字节数获取局部变量存储空间。被调函数返回(ret)时,将esp加上相应字节数,归还栈空间,弹出主调函数压在栈中的代码执行指针(eip),跳回主调函数。再由主调函数恢复到调用前的栈。       

ENO·REZ @ 优快云 BLOG 7556

C++数据结构之栈

栈的应用场景非常广泛,包括代码中的解析、数据结构中的树和图的遍历以及计算机系统中的内存分配等等。本文会介绍栈。

现役 OIer。 1万+

数据结构链栈基本操作(C/C++实现)

数据结构链栈基本操作(C/C++实现) 注意:本代码为了测试运行默认含有操作所需数据,如有需要可自己增删改相关数据 涉及基本运算流程 1.初始化栈 2.判断栈是否非空 3.元素依次进栈 4.判断栈是否非空 5.输出出栈序列 6.判断栈s是否非空 7.释放栈 GitHub地址(包含.cpp文件和可执行程序exe) 我的数据结构GitHub地址 源代码(经VS2015、devC++编译器运行通过) #...

JunsIr的技术栈 2174

STM32CubeMX和华为LiteOS Studio开发STM32

传统的STM32的开发通常使用Keil/IAR这类开发软件,随着物联网时代的到来,传统嵌入式的发展不断向物联网方向靠拢,而Keil/IAR这类开发软件无法满足IoT一站式的开发,华为LiteOS Studio结合STM32CubeMX可以快速,高效地进行物联网开发,本文提供一种开发思路及环境的配置方法。...

weixin_45680600的博客 2832

c语言用顺序栈显示栈中元素,顺序栈的c语言实现

1.顺序栈结构typedef struct{SElemType data[MAXSIZE];int top; /* 用于栈顶指针 */}SqStack;2.构造一个空栈SStatus InitStack(SqStack *S){/* S.data=(SElemType *)malloc(MAXSIZE*sizeof(SElemType)); */S->top=-1;return OK;}3....

weixin_36308543的博客 2036

Rockchip rv1126平台在gstreamer1中添加OpenCv实现视频流负片的效果

rv1126 gstreamer opencv negetive effect

Aisy_D的专栏 1463

必看,C/C++学习路线,C++基础到高级方法指南

C/C++学习路线之C++基础到高级方法指南 C/C++遍布的领域有后端服务器,移动互联网后端,经典Windows界面开发,移动互联网端界面开发,跨平台界面开发,图形分析,系统架构,应用设计,还有现在最为流行的分布架构等一些新的技术领域。所以说:C/C++俨然已成为一门贵族语言,成为了编程界最重要的语言之一。   C/C++入门阶段 刚入门的时候我们主要是学习培养编程思维和动手能力,深刻理...

7564

VMwareWorkstation安装UOS系统(1070版本)教程

UOS系统是一款国产信创操作系统。目前市面上主流的系统版本是1070,下面我们用虚拟机来安装一下这款系统。

欲买桂花同载酒的博客 4290

CAPL 中的变量类型详解与应用

CAPL 中的变量类型详解与应用

qq_42268594的博客 1448

视频教程-CPP语言系列--视频精讲-C/C++

CPP语言系列--视频精讲 毕业于清华大学,曾担任Google算法工程师,微...

weixin_29030223的博客 506

【斯坦福计网CS144项目】环境配置 & Lab0: ByteStream

前言 感觉学了不少 C++ 编程的知识和技术但比较缺少实践,于是打算找一些项目跟着做一做。 首先安利一个自学网站 CS自学指南,北大的同学做的,汇总了很多国内外高校 CS 相关的高质量公开课,其中大部分是有课程项目的。翻了翻感觉 Stanford 的这门 CS144 计网课的 Lab 比较有趣,难度也不错,就是它了! 课程网址:CS 144: Introduction to Computer Networking 我跟的是 2021 Fall 学期的版本。 准备工作 在上面的网站中先把 8 个实验的文档(

アルタイル 8163

C/C++ 数据结构 —— 栈

栈是一种常见的数据结构,它按照后进先出(Last In First Out,LIFO)的原则组织数据。其可视作是一个有顺序的集合。想象一个盘子叠放的过程,新放入的盘子总是放在最上面,而取出的时候也是从最上面的盘子开始拿。在栈中,数据项的添加(入栈)和删除(出栈)都只能在栈顶进行。例如,一个栈的初始状态为空,当依次将元素 A、B、C 入栈后,栈顶元素是 C。如果此时进行出栈操作,那么 C 会先被移除,接着是 B,最后是 A。栈是一种非常基础且重要的数据结构,在计算机科学的很多领域都有广泛的应用。

2401_87692970的博客 2098

CosyVoice语音合成使用教程

CosyVoice是一款开源的语音合成工具,它基于深度学习模型,能够生成高度逼真的语音内容。该工具支持多种语言的语音生成,包括中文、英文、日文、粤语和韩语。CosyVoice的亮点在于它对生成语音情感和韵律的精细控制,通过富文本或自然语言输入,可以显著提升合成语音的情感表达能力。CosyVoice提供了多种预训练模型,用户可以根据需求选择合适的模型。:基底模型,适用于一般语音合成任务。:经过SFT微调的模型,适用于特定音色和情感的语音合成。:支持Instruct微调的模型,适用于自然语言控制的语音合成。

笔者从事电信媒体开发多年,愿意将多年的开发经验分享给同行 4442

用MSBlock重塑C2f,让你的模型又轻又强(参数量与精度的双重突破)

打开确保模型解析器能识别MSBlock模块。通过将MSBlock集成到YOLOv8的C2f模块中,我们实现了一个“轻量且多尺度感知”的目标检测模型。这个改进不仅在工程上能降低部署成本、提升推理速度,更在科研上提供了“多尺度+动态核”的创新思路——这种思路可以延伸到其他网络(如ResNet、MobileNet)的改进中,帮你在论文中打造独特的研究点。如果你在实现过程中遇到问题,比如代码报错、训练收敛异常,可以先检查模块集成的每一步是否到位,再尝试调整MSBlock的卷积核尺寸、动态权重的计算方式等超参数。

m0_71589036的博客 105

c/c++中入栈顺序

c/c++中的都是从右往左入栈的,在调用函数时,若参数需要运算则先运算,然后入栈,再调用函数。 分析下面代码的运算结果: int main() { /* 1. 入栈顺序,参数从右往左入栈 2. 计算顺序,先入栈的先计算;计算完后再入栈 3. 传递的参数:实际变量,还是临时变量 */ int i=1; // 先计算,两次i++后i的值为3;传递的是实际变量i的值 printf("%d,%d\n", ++i, ++i); //3,3 // i+

David 7015

常用元器件使用方法3:电平转换芯片74LVC1T45的使用方法

介绍: 74LVC1T45是一个单位双向可控电平转换芯片。   芯片特性: 1、宽供给电压范围:1.65V到5.5V; 2、3.3V时,可输出24mA电流; 3、最大16uA电能损耗; 4、高噪音抑制;   型号:   引脚: VCC(A) 1 A端和DIR电源 GND 2 地 A 3 数据输入/输出 B 4 ...

snmplink的博客 1万+

链栈的基本操作C/C++代码实现

链栈的结构: 由于栈的主要操作是在栈顶插入和删除, 显然以链表的头部作为栈顶是最方便的,且不需要附加一个头结点。 初始化: 栈顶指针S置空即可。 入栈: 链栈不需要判断栈是否满! 出栈: 栈顶指针S等于NULL表空栈,即链栈S==NULL时为空栈。 代码如下: #include<stdio.h> #include<stdlib.h> #define MAXSIZE 100 typedef int SElemType; //链栈的存储结构 typedef struct Sta

Ycy的博客 4747

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

迈向C/C++与前端的全栈开发之路

大家好,我是一名正在学习编程的爱好者,目前对C/C++和前端开发充满了兴趣。相比于单一方向,我更希望能够成为一名全栈开发者,同时掌握后端的高性能编程和前端的用户交互设计。我认为,全栈开发不仅能帮助我全面理解一个项目的各个部分,还能让我在未来的开发过程中拥有更大的灵活性。

weixin_44643253的博客 1803

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

C语言系列1——综述

终于把CPrimerPlus刷完了,在此总结一下C的基础知识点,方便日后查阅学习。本文章可自由转载。 目录: 文章目录1. 初识C语言2.C基础2.1编译器和编辑器2.2 安装编译器2.3 MinGw和VScode搭建C环境2.4 MinGw和notepad++搭建C环境2.5 Visual Studio201X 1. 初识C语言   C语言是贝尔实验室的丹尼斯·里奇(Dennis Ritch)和...

既往不恋未来不迎 871

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Vscode +Msys2配置C/C++环境

选择默认路径安装或者自定义路径即可(切记不要有中文路径名,NTFS 卷上仅 ASCII 的短路径,无重音,无空格,无符号链接,无 subst 或网络驱动器,无 FAT)。更新其余基本软件包完成后,输入以下命令完成mingw工具链安装(这条命令是全部安装,会有一些用不到的工具)),在搜索框中输入“C++”,修改以下配置:(编译器路径为上面安装的MSYS2下的gcc路径)编译器安装完成后,在cmd窗口输入下面命令,检查编译器配置是否成功。在官网下载完成后,直接安装就行,需要注意的是安装路径不能有中文。

AiENG_07的博客 8499

C/C++学习路线 (系统的学习路线

C/C++学习路线 随着互联网及互联网+深入蓬勃的发展,经过40余年的时间洗礼,C/C++俨然已成为一门贵族语言,出色的性能使之成为高级语言中的性能王者。而在今天,它又扮演着什么样重要的角色呢?请往下看: 后端服务器,移动互联网后端,经典Windows界面开发,移动互联网端界面开发,跨平台界面开发,图形分析,系统架构,应用设计,还有现在最为流行的分布架构等一些新的技术领域。 这么牛的语言,...

我从小酷到大的 2250

C/C++编程:log4cpp使用学习

简介 Log4cpp是一个开源的C++类库,它提供了在C++程序中使用日志和跟踪调试的功能。使用log4cpp,可以很便利地将日志或者跟踪调试信息写入字符流、内存字符串队列、文件、回滚文件、调试器、Windows日志、本地syslog和远程syslog服务器中。 Log4cpp有如下优点: 提供了可扩展的多种日志记录方式; 提供了NDC(嵌套诊断上下文),可用于多线程、多场景的跟踪调试; 提供了完整的日志动态优先级控制,可随时调整需要记录的日志优先级 可通过配置文件完成所有配置并动态加载; 性能优秀,内存

OceanStar的博客 4019

C/C++ 调用约定:深入理解栈与平栈

C 调用约定与 C++ 调用约定:深入理解栈与平栈

re1ife的博客 1275

C/C++的内存分配?栈和堆的区别?为什么栈快?

一个由 C/C++ 编译的程序占用的内存分为以下几个部分 : 栈区( stack ) ——由编译器自动分配释放,存放为运行函数而分配的局部变量、函数参数、返回数据、返回地址等。其操作方式类似于数据结构中的栈; 堆区( heap )——一般由程序员分配释放, 若程序员不释放,程序结束时可能由 OS 回收 。分配方式类似于链表; 全局区(静态区)(static)——存放全局变量、静态数据。初始化的...

honeyJ 9238
上一篇: 学习C/C++语言系列(1)双向循环带哨兵位链表
下一篇: 学习C/C++系列(3)列
roseisbule
博客等级 码龄5年 217粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

roseisbule

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值