【数据结构与算法 经典例题】使用栈实现队列(图文详解)

news2024/9/20 14:49:01

             💓 博客主页:倔强的石头的CSDN主页 

             📝Gitee主页:倔强的石头的gitee主页

   ⏩ 文章专栏:《数据结构与算法 经典例题》C语言

                                  期待您的关注

1b7335aca73b41609b7f05d1d366f476.gif

目录

​​一、问题描述 

二、前置知识

三、解题思路

原理:

 图解:

注:

四、C语言实现代码 

🍃栈实现代码:

🍃栈实现队列代码:

🍃测试文件及结果:


​​一、问题描述 

原题出自

232. 用栈实现队列 - 力扣(LeetCode)

二、前置知识

关于栈的详细讲解请阅读这篇文章

【数据结构与算法】使用数组实现栈:原理、步骤与应用-CSDN博客

 关于队列的详细讲解请阅读这篇文章

【数据结构与算法】使用单链表实现队列:原理、步骤与应用-CSDN博客

三、解题思路

使用两个栈(Stack)来实现队列(Queue)的功能是一个经典的算法问题。栈和队列在数据结构上是两种完全不同的类型(栈是后进先出,队列是先进先出),解决问题的关键就在于如何巧妙地利用两个栈的后进先出的特性来模拟队列先进先出的行为。

原理:

  1. 结构定义我们定义两个栈,stack1 和 stack2。其中一个栈(例如 stack1)用于入队操作,另一个栈(例如 stack2)用于出队操作。
  2. 入队操作所有元素都压入 stack1
  3. 出队操作
    • 如果 stack2 不为空,直接从 stack2 弹出栈顶元素,作为出队元素。
    • 如果 stack2 为空,则将 stack1 中的所有元素逐个弹出并压入 stack2(这个操作实际上是将 stack1 的元素反转后压入 stack2),然后再从 stack2 弹出栈顶元素,作为出队元素。
  4. 取队首元素类似出队操作,只是最后支取栈顶元素,不出栈

 图解:

(为方便理解对队列的结构进行了简化)

取队首元素类似于出队列,只是取出的元素不出栈

注:

另外还有一种可行的实现方式:

结构定义一个栈用来出队列和入队列,另一个栈保持为空,只用来移动数据

  1. 入队列都入到非空栈
  2. 出队列先将非空栈的所有元素(除了最后一个)移到空栈,最后的元素出栈并返回,并将移出的元素移动回来恢复顺序
  3. 取队首元素先将非空栈的所有元素(除了最后一个)移到空栈,最后的元素返回,再将移出的元素移动回来恢复顺序

这种方法在理论上是可行的,只不过每次出队列或取队首元素都需要将栈的元素移动两遍,效率比较低,因此这里就不给出实现代码了,建议使用第一种方式

四、C语言实现代码 

🍃栈实现代码:

// 支持动态增长的栈
typedef int STDataType;//对数据类型重命名,方便后期修改类型
typedef struct Stack
{
	STDataType* a;
	int top;		// 栈顶
	int capacity;  // 容量 
}Stack;//定义结构同时重命名
// 初始化栈 
void StackInit(Stack* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}

// 入栈 
void StackPush(Stack* ps, STDataType data)
{
	assert(ps);
	//判断是否需要扩容
	if (ps->top == ps->capacity)
	{
		int newcapa = ps->capacity == 0 ? 4 : 2 * (ps->capacity);
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newcapa);
		if (tmp == NULL)
		{
			perror("realloc\n");
			exit(1);
		}
		ps->a = tmp;
		ps->capacity = newcapa;
	}
	//确定空间足够之后再插入数据
	ps->a[ps->top] = data;
	ps->top++;
}

// 出栈 
void StackPop(Stack* ps)
{
	assert(ps);
	assert(ps->top);

	ps->top--;
}

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

// 获取栈中有效元素个数 
int StackSize(Stack* ps)
{
	assert(ps);

	return ps->top;
}

// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
int StackEmpty(Stack* ps)
{
	assert(ps);

	return ps->top == 0;
}

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

🍃栈实现队列代码:

typedef struct {
	Stack pushst;//入数据的栈
	Stack popst;//出数据的栈
} MyQueue;


MyQueue* myQueueCreate() //初始化
{
	MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
	StackInit(&(obj->pushst));
	StackInit(&(obj->popst));
	return obj;
}

void myQueuePush(MyQueue* obj, int x) //模拟入队列
{
	assert(obj);
	StackPush(&(obj->pushst), x);//入队列直接插入到pushst栈
}

int myQueuePop(MyQueue* obj) //模拟出队列
{
	assert(obj);
	assert(!StackEmpty(&(obj->popst)) || !StackEmpty(&(obj->pushst)));//首先两个栈不能都为空
	if (StackEmpty(&(obj->popst)))//如果popst栈为空,把数据倒过去
	{
		while (obj->pushst.top)
		{
			StackPush(&(obj->popst), StackTop(&(obj->pushst)));
			StackPop (&(obj->pushst));
		}
	}
	int top = StackTop(&(obj->popst));
	StackPop(&(obj->popst));//再从popst栈出数据
	return top;
}

int myQueuePeek(MyQueue* obj) //模拟取队列首元素
{
	assert(obj);
	assert(!StackEmpty(&(obj->popst)) || !StackEmpty(&(obj->pushst)));
	if (StackEmpty(&(obj->popst)))//如果popst栈为空,把数据倒过去
	{
		while (obj->pushst.top)
		{
			StackPush(&(obj->popst), StackTop(&(obj->pushst)));
			StackPop(&(obj->pushst));
		}
	}
	return StackTop(&(obj->popst));
}

bool myQueueEmpty(MyQueue* obj) //模拟队列判空
{
	return StackEmpty(&(obj->pushst)) && StackEmpty(&(obj->popst));
}

void myQueueFree(MyQueue* obj) //销毁
{
	StackDestroy(&(obj->pushst));
	StackDestroy(&(obj->popst));
	free(obj);
	obj = NULL;
}

🍃测试文件及结果:

void test2()
{
	MyQueue* Queue = myQueueCreate();
	if (myQueueEmpty(Queue))
		printf("队列空\n");
	else
		printf("队列非空\n");
	myQueuePush(Queue, 1);
	myQueuePush(Queue, 2);
	myQueuePush(Queue, 3);
	myQueuePush(Queue, 4);
	printf("队首元素 %d\n", myQueuePeek(Queue));
	if (myQueueEmpty(Queue))
		printf("队列空\n");
	else
		printf("队列非空\n");
	while (!myQueueEmpty(Queue))
	{
		printf("%d ", myQueuePop(Queue));
	}
	printf("\n");
	if (myQueueEmpty(Queue))
		printf("队列空\n");
	else
		printf("队列非空\n");
	myQueueFree(Queue);
}

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

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

相关文章

【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(十六)

课程地址: 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程,一套精通鸿蒙应用开发 (本篇笔记对应课程第 25 - 26 节) P25《24.Stage模型-UIAblity生命周期》 stage之所以叫这个名字,是因为它在运行时&#xff0…

骚操作:如何让一个网页一直处于空白情况?

🧑‍💻 写在开头 点赞 收藏 学会🤣🤣🤣 如题,惯性思路很简单,就是直接撸上一个空内容的html。 注:以下都是在现代浏览器中执行,主要为**Chrome 版本 120.0.6099.217&…

TPS61085非同步650kHz,1.2MHz, 18.5V升压DCDC芯片

1 特点 TPS61085外观和丝印PMKI 2.3 V 至 6 V 输入电压范围 具有 2.0A 开关电流的 18.5V 升压转换器 650kHz/1.2MHz 可选开关频率 可调软启动 热关断 欠压闭锁 8引脚VSSOP封装 8引脚TSSOP封装 2 应用 手持设备 GPS接收器 数码相机 便携式应用 DSL调制解调器 PCMCIA卡 TFT LCD…

ChatGPT API教程在线对接OpenAI APIKey技术教程

一、OpenAI基本库介绍 您可以通过 HTTP 请求与 API 进行交互,这可以通过任何编程语言实现。我们提供官方的 Python 绑定、官方的 Node.js 库,以及由社区维护的库。 要安装官方的 Python 绑定,请运行以下命令: pip install open…

全国计算机二级C++题库笔记

全国计算机二级C题库笔记 Ⅰ. 选择题专项训练1 公共基础部分2 二级C程序设计第1~4章》每章标题1. C标识符命名规则2. 面向对象的三个主要特征3. C的四个开发步骤4. 关于类和对象的叙述5. !和&&的作用6. C枚举类型初值问题7. ASCII码对照表8. 运算符两边的数据类型&…

ONLYOFFICE 8.1版本桌面编辑器深度体验:创新功能与卓越性能的结合

ONLYOFFICE 8.1版本桌面编辑器深度体验:创新功能与卓越性能的结合 随着数字化办公的日益普及,一款高效、功能丰富的办公软件成为了职场人士的必备工具。ONLYOFFICE团队一直致力于为用户提供全面而先进的办公解决方案。最新推出的ONLYOFFICE 8.1版本桌面编…

08.QT控件:QWidget

一、Widget 简介 Widget 是 Qt 中的核⼼概念.。英⽂原意是 "小部件",我们此处也把它翻译为 "控件"。控件是构成⼀个图形化界⾯的基本要素。 Qt 作为⼀个成熟的 GUI 开发框架, 内置了⼤量的常⽤控件。并且 Qt 也提供了 "⾃定义控件" 的…

C和C++实现stack的对比

本篇文章,我们将对比C语言和C实现栈的不同来体会C的魅力! 1.栈的介绍 栈(Stack)是一种常见的数据结构,它是一种特殊的线性表,只允许在一端进行数据的插入和删除操作。这一端通常被称为栈顶(Top…

移位操作符

目录 移位 >> --- 右移操作符 右移操作符代码的使用 代码验证 算术右移和逻辑右移 验证Visual Studio使用的是算术右移还是逻辑右移 逻辑右移 or 算术右移的代码验证 右移操作符对正整数有除2的效果&#xff08;除2是整数除法的除2&#xff09; 验证 << -…

Day3:203 移除链表元素 707设计链表 206反转链表

题目&#xff1a;206. 反转链表 - 力扣&#xff08;LeetCode&#xff09; /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* …

[数据集][目标检测]棉花检测数据集VOC+YOLO格式389张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;389 标注数量(xml文件个数)&#xff1a;389 标注数量(txt文件个数)&#xff1a;389 标注类别…

Excel如果将一个表格拆分为多个表格,文末另赠彩蛋!

前期分享如何用数据透视表将一个表格拆分成多个工作薄Excel一个表格拆分多个表格&#xff0c;你学会了吗&#xff1f; 今天刘小生分享另外一种&#xff0c;如果拆分成多个工作表格文件&#xff01; 如何将一个表格根据部门进行拆分成多个表格&#xff0c;再点对点发送给各部门…

浅析Vite本地构建原理

前言 随着Vue3的逐渐普及以及Vite的逐渐成熟&#xff0c;我们有必要来了解一下关于vite的本地构建原理。 对于webpack打包的核心流程是通过分析JS文件中引用关系&#xff0c;通过递归得到整个项目的依赖关系&#xff0c;并且对于非JS类型的资源&#xff0c;通过调用对应的loade…

宝宝早教电子图书 酷得电子方案

宝宝早教发声书是一种专为婴幼儿设计的图书&#xff0c;旨在通过有趣的图画和声音来吸引宝宝的注意力&#xff0c;帮助他们学习语言、认知和发展各种技能。这类书籍通常包括以下特点&#xff1a; 鲜艳的图画&#xff1a;发声书通常配有色彩鲜艳、形象生动的图画&#xff0c;以…

什么美业系统好用?美业门店收银系统源码分享、小程序展示

专业美业系统与普通系统相比&#xff0c;更加贴合美业门店的经营需求&#xff0c;提供了更全面、便捷、高效的管理功能&#xff0c;有助于提升门店的服务质量和经营效益。 博弈美业系统包括PC、iPad、手机、小程序四大端口&#xff0c;满足不同人群的各种需求。客户可从小程序…

使用Leaflet和瓦片地图实现离线地图的技术指南

引言 在现代的Web应用中&#xff0c;地图服务扮演着越来越重要的角色。然而&#xff0c;在一些特殊环境下&#xff0c;如偏远地区或网络环境不稳定的情况下&#xff0c;依赖在线地图服务可能会受到限制。因此&#xff0c;实现离线地图功能成为了一个重要的需求。本文将介绍如何…

Jenkins定时构建自动化(四):Python 的 argparse 模块

目录 一、主要功能和用途 二、核心类和方法 三、总结 四、argparse模块示例 Jenkins定时构建自动化(一)&#xff1a;Jenkins下载安装配置-CSDN博客 Jenkins定时构建自动化(二)&#xff1a;Jenkins的定时构建-CSDN博客 Jenkins定时构建自动化(三)&#xff1a;手动定时构建…

【服务器08】之【游戏框架】之【加载主角】

首先简单了解一下帧率 FixedUpdate( ) > Update( ) > LateUpdate( ) 首先FixedUpdate的设置值 默认一秒运行50次 虽然默认是0.02秒&#xff0c;但FiexedUpdate并不是真的0.02秒调用一次&#xff0c;因为在脚本的生命周期内&#xff0c;FixedUpdate有一个小循环&…

嵌入式开发板屏幕显示汉字

一、实验目的 1&#xff0e;编写能够在嵌入式开发板LCD上显示汉字的程序&#xff1b; 2&#xff0e;在Ubuntu系统中编译上述程序生成可执行文件&#xff1b; 3&#xff0e;到开发板中验证。 二、实验步骤 1. Ubuntu系统上编写验证程序 Ubuntu系统上编写的验证程序如下&…

【亲测好用】神级PSAI插件大揭秘:三款创成式修图神器,让你解放双手

PsBeta被停用后&#xff0c;小编一直想找到能够平替PsBeta创成式填充功能的插件。 功夫不负有心&#xff0c;终于被我找到啦&#xff0c;现在就给大家揭秘这三款宝藏修图神器&#xff0c;希望能够帮到大家。 1.插件名称&#xff1a;Starai 无需科学上网&#xff0c;还自带提示…