当前位置: 首页 > news >正文

用队列实现栈——数据结构与算法

在这里插入图片描述
请添加图片描述

😶‍🌫️Take your time ! 😶‍🌫️
💥个人主页:🔥🔥🔥大魔王🔥🔥🔥
💥代码仓库:🔥🔥魔王修炼之路🔥🔥
💥所属专栏:🔥魔王的修炼之路–数据结构🔥
如果你觉得这篇文章对你有帮助,请在文章结尾处留下你的点赞👍和关注💖,支持一下博主。同时记得收藏✨这篇文章,方便以后重新阅读。


文章目录

  • 一、题目
  • 二、思路
  • 三、代码
    • 1、队列代码
    • 2、创建两个队列模拟的栈
    • 3、入栈
    • 4、出栈
    • 5、访问栈顶元素
    • 6、判断栈是否为空
    • 7、释放空间
    • 8、总代码
  • 四、总结

一、题目

力扣链接

在这里插入图片描述

二、思路

栈是后进先出,队列是先进先出.

出队列:队列入了1,2,3,4后只能1,2,3,4出,栈入了1,2,3,4后只能4,3,2,1出,所以需要两个队列,当栈出元素时,先让前n-1个入到另一个队列并删除原队列中这n-1个数据,那么原来队列只剩下4了,然后把这个4删除就行。

在这里插入图片描述

入队列:根据出队列发现,把一个队列数据放到另一个数据里面,原来的数据顺序不变,所以入队列时只需要入在那个不为空的队列里就行。

在这里插入图片描述

三、代码

1、队列代码

首先先把之前实现队列的代码粘贴上去,这样就不用再实现一遍队列了。

#include <stdlib.h>typedef int QDataType;typedef struct QueueNode
{struct QueueNode* next;QDataType data;
}QNode;typedef struct Queue
{QNode* head;QNode* tail;int size;
}Queue;void QInit(Queue* q)
{assert(q);q->head = q->tail = NULL;q->size = 0;
}void QDestroy(Queue* q)
{assert(q);while (q->head){QNode* next = q->head->next;free(q->head);q->head = next;}q->tail = NULL;q->size = 0;
}QNode* BuyNewnode(QDataType x)
{QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc error");assert(newnode);}newnode->data = x;newnode->next = NULL;return newnode;
}void QPush(Queue* q, QDataType x)
{assert(q);QNode* newnode = BuyNewnode(x);if (q->head == NULL){assert(q->head == q->tail);q->head = q->tail = newnode;}else{q->tail->next = newnode;q->tail = newnode;}q->size++;
}void QPop(Queue* q)
{assert(q);assert(q->head && q->tail);if (q->head->next == NULL){assert(q->head == q->tail);free(q->head);q->head = q->tail = NULL;}else{QNode* newhead = q->head->next;free(q->head);q->head = newhead;}q->size--;
}int QSize(Queue* q)
{assert(q);return q->size;
}bool QEmpty(Queue* q)
{assert(q);//-------------------------1------------------------------------------------//1这里的报错,但是其实根本没错,是在下面的2处错的,所以在哪个地方报错可以重点看那个地方,但并不一定就是这个部分错了。return q->size == 0;
}QDataType QFront(Queue* q)
{assert(q);assert(q->head);return q->head->data;
}QDataType QBack(Queue* q)
{assert(q);assert(!QEmpty(q));return q->tail->data;
}

2、创建两个队列模拟的栈

创建一个结构体,放两个队列作为成员,然后创建并初始化队列。

//匿名结构体,创建一个结构体是我的栈,因为我们使用队列模拟栈,所以里面放两个队列。
typedef struct {Queue q1;Queue q2;
} MyStack;//创建我的栈,前面我们的模拟栈的结构体已经创建好了,现在就是要创建一个指针指向我们开辟出的该结构体的空间,并使其初始化。因为这是创建好后用的返回值传给别的函数,所以不能直接创建变量,要malloc,否则除该作用域就销毁了。
MyStack* myStackCreate() {MyStack* creat = (MyStack*)malloc(sizeof(MyStack));if(creat == NULL){perror("malloc error");assert(creat);}QInit(&creat->q1);QInit(&creat->q2);return creat;
}

3、入栈

直接入到不为空的队列就行,因为两个相互导顺序还是原来的顺序。

在这里插入图片描述

void myStackPush(MyStack* obj, int x) {Queue* EmptyQ = &obj->q1;Queue* nonEmptyQ = &obj->q2;//if (QEmpty(&EmptyQ) == 0)-------------------------2(错的)----------------------------------if (QEmpty(EmptyQ) == 0){EmptyQ = &obj->q2;nonEmptyQ = &obj->q1;}QPush(nonEmptyQ, x);
}

4、出栈

让不为空的n-1个元素导到空队列中,原队列只剩最后一个,然后pop就行了。

在这里插入图片描述

int myStackPop(MyStack* obj) {Queue* EmptyQ = &obj->q1;Queue* nonEmptyQ = &obj->q2;if (!QEmpty(EmptyQ)){EmptyQ = &obj->q2;nonEmptyQ = &obj->q1;}while (QSize(nonEmptyQ) != 1){QPush(EmptyQ, QFront(nonEmptyQ));QPop(nonEmptyQ);}int ret = QFront(nonEmptyQ);QPop(nonEmptyQ);return ret;
}

5、访问栈顶元素

可以直接访问非空队列的最上面的元素即可。

//方法1.访问栈顶元素
int myStackTop(MyStack* obj) {if(!QEmpty(&obj->q1)){return QBack(&obj->q1);}elsereturn QBack(&obj->q2);
}

也可以再导一次,就像出栈一样,只不过不删除最后的元素,而是也导入另一个队列。

//方法2.访问栈顶元素
// 力扣检查比较严格,就算最后的那个return没用,但有返回值的函数结尾还是要加上return 的。
int myStackTop(MyStack* obj) {int ret = 0;Queue* EmptyQ = &obj->q1;Queue* nonEmptyQ = &obj->q2;if(!QEmpty(EmptyQ)){EmptyQ = &obj->q2;nonEmptyQ = &obj->q1;}while(QSize(nonEmptyQ)>0){if(QSize(nonEmptyQ) == 1){ret = QFront(nonEmptyQ);QPush(EmptyQ,QFront(nonEmptyQ));QPop(nonEmptyQ);return ret;}QPush(EmptyQ,QFront(nonEmptyQ));QPop(nonEmptyQ);}return ret;
}

6、判断栈是否为空

两个队列同时为空即为空。

bool myStackEmpty(MyStack* obj) {return QEmpty(&obj->q1) && QEmpty(&obj->q2);
}

7、释放空间

malloc了几次就释放几次。

void myStackFree(MyStack* obj) {QDestroy(&obj->q1);QDestroy(&obj->q2);free(obj);
}

8、总代码

#include <stdlib.h>typedef int QDataType;typedef struct QueueNode
{struct QueueNode* next;QDataType data;
}QNode;typedef struct Queue
{QNode* head;QNode* tail;int size;
}Queue;void QInit(Queue* q)
{assert(q);q->head = q->tail = NULL;q->size = 0;
}void QDestroy(Queue* q)
{assert(q);while (q->head){QNode* next = q->head->next;free(q->head);q->head = next;}q->tail = NULL;q->size = 0;
}QNode* BuyNewnode(QDataType x)
{QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc error");assert(newnode);}newnode->data = x;newnode->next = NULL;return newnode;
}void QPush(Queue* q, QDataType x)
{assert(q);QNode* newnode = BuyNewnode(x);if (q->head == NULL){assert(q->head == q->tail);q->head = q->tail = newnode;}else{q->tail->next = newnode;q->tail = newnode;}q->size++;
}void QPop(Queue* q)
{assert(q);assert(q->head && q->tail);if (q->head->next == NULL){assert(q->head == q->tail);free(q->head);q->head = q->tail = NULL;}else{QNode* newhead = q->head->next;free(q->head);q->head = newhead;}q->size--;
}int QSize(Queue* q)
{assert(q);return q->size;
}bool QEmpty(Queue* q)
{assert(q);//-------------------------1------------------------------------------------//1这里的报错,但是其实根本没错,是在下面的2处错的,所以在哪个地方报错可以重点看那个地方,但并不一定就是这个部分错了。return q->size == 0;
}QDataType QFront(Queue* q)
{assert(q);assert(q->head);return q->head->data;
}QDataType QBack(Queue* q)
{assert(q);assert(!QEmpty(q));return q->tail->data;
}//匿名结构体,创建一个结构体是我的栈,因为我们使用队列模拟栈,所以里面放两个队列。
typedef struct {Queue q1;Queue q2;
} MyStack;//创建我的栈,前面我们的模拟栈的结构体已经创建好了,现在就是要创建一个指针指向我们开辟出的该结构体的空间,并使其初始化。因为这是创建好后用的返回值传给别的函数,所以不能直接创建变量,要malloc,否则除该作用域就销毁了。
MyStack* myStackCreate() {MyStack* creat = (MyStack*)malloc(sizeof(MyStack));if(creat == NULL){perror("malloc error");assert(creat);}QInit(&creat->q1);QInit(&creat->q2);return creat;
}void myStackPush(MyStack* obj, int x) {Queue* EmptyQ = &obj->q1;Queue* nonEmptyQ = &obj->q2;//if (QEmpty(&EmptyQ) == 0)-------------------------2----------------------------------if (QEmpty(EmptyQ) == 0){EmptyQ = &obj->q2;nonEmptyQ = &obj->q1;}QPush(nonEmptyQ, x);
}int myStackPop(MyStack* obj) {Queue* EmptyQ = &obj->q1;Queue* nonEmptyQ = &obj->q2;if (!QEmpty(EmptyQ)){EmptyQ = &obj->q2;nonEmptyQ = &obj->q1;}while (QSize(nonEmptyQ) != 1){QPush(EmptyQ, QFront(nonEmptyQ));QPop(nonEmptyQ);}int ret = QFront(nonEmptyQ);QPop(nonEmptyQ);return ret;
}// //方法1.访问栈顶元素
// int myStackTop(MyStack* obj) {
//     if(!QEmpty(&obj->q1))
//     {
//         return QBack(&obj->q1);
//     }
//     else
//         return QBack(&obj->q2);
// }//方法2.访问栈顶元素
// 力扣检查比较严格,就算最后的那个return没用,但有返回值的函数结尾还是要加上return 的。
int myStackTop(MyStack* obj) {int ret = 0;Queue* EmptyQ = &obj->q1;Queue* nonEmptyQ = &obj->q2;if(!QEmpty(EmptyQ)){EmptyQ = &obj->q2;nonEmptyQ = &obj->q1;}while(QSize(nonEmptyQ)>0){if(QSize(nonEmptyQ) == 1){ret = QFront(nonEmptyQ);QPush(EmptyQ,QFront(nonEmptyQ));QPop(nonEmptyQ);return ret;}QPush(EmptyQ,QFront(nonEmptyQ));QPop(nonEmptyQ);}return ret;
}//方法3.访问栈顶元素
// int myStackTop(MyStack* obj) {
// 	Queue* EmptyQ = &obj->q1;
// 	Queue* nonEmptyQ = &obj->q2;
// 	if (!QEmpty(EmptyQ))
// 	{
// 		EmptyQ = &obj->q2;
// 		nonEmptyQ = &obj->q1;
// 	}
// 	while (QSize(nonEmptyQ) != 1)
// 	{
// 		QPush(EmptyQ, QFront(nonEmptyQ));
// 		QPop(nonEmptyQ);
// 	}
// 	int ret = QFront(nonEmptyQ);
// 	QPush(EmptyQ,QFront(nonEmptyQ));
// 	QPop(nonEmptyQ);
// 	return ret;
// }bool myStackEmpty(MyStack* obj) {return QEmpty(&obj->q1) && QEmpty(&obj->q2);
}void myStackFree(MyStack* obj) {QDestroy(&obj->q1);QDestroy(&obj->q2);free(obj);
}/*** Your MyStack struct will be instantiated and called as such:* MyStack* obj = myStackCreate();* myStackPush(obj, x);* int param_2 = myStackPop(obj);* int param_3 = myStackTop(obj);* bool param_4 = myStackEmpty(obj);* myStackFree(obj);
*/

四、总结

  • -----1-----和-----2-----这两个地方是一个错误,因为在2多写了个取地址,然后在1处报错,结果检查了大半天也检查不出来,因为1处报错很难想出来是2处的问题。所以:报错的地方重点检查,如果真的没错误,可能是其他地方的问题。
  • 分别指向空队列和非空队列时别弄混了,有点绕。

  • 博主长期更新,博主的目标是不断提升阅读体验和内容质量,如果你喜欢博主的文章,请点个赞或者关注博主支持一波,我会更加努力的为你呈现精彩的内容。

🌈专栏推荐
😈魔王的修炼之路–C语言
😈魔王的修炼之路–数据结构初阶
😈魔王的修炼之路–C++
😈魔王的修炼之路–Linux
更新不易,希望得到友友的三连支持一波。收藏这篇文章,意味着你将永久拥有它,无论何时何地,都可以立即找到重新阅读;关注博主,意味着无论何时何地,博主将永久和你一起学习进步,为你带来有价值的内容。

请添加图片描述

相关文章:

用队列实现栈——数据结构与算法

&#x1f636;‍&#x1f32b;️Take your time ! &#x1f636;‍&#x1f32b;️ &#x1f4a5;个人主页&#xff1a;&#x1f525;&#x1f525;&#x1f525;大魔王&#x1f525;&#x1f525;&#x1f525; &#x1f4a5;代码仓库&#xff1a;&#x1f525;&#x1f525;魔…...

Python“牵手”1688商品详情页数据采集方法,1688API接口申请指南

1688详情接口 API 是开放平台提供的一种 API 接口&#xff0c;它可以帮助开发者获取商品的详细信息&#xff0c;包括商品的标题、描述、图片等信息。在电商平台的开发中&#xff0c;详情接口API是非常常用的 API&#xff0c;因此本文将详细介绍详情接口 API 的使用。 一、1688…...

记录第一篇被”华为开发者联盟鸿蒙专区 “收录的文章

记录第一篇被”华为开发者联盟鸿蒙专区 “社区收录的文章。 坚持写作的动力是什么&#xff1f; 是记录、分享&#xff0c;以及更好的思考 。...

jenkins的cicd操作

cicd概念 持续集成&#xff08; Continuous Integration&#xff09; 持续频繁的&#xff08;每天多次&#xff09;将本地代码“集成”到主干分支&#xff0c;并保证主干分支可用 持续交付&#xff08;Continuous Delivery&#xff09; 是持续集成的下一步&#xff0c;持续…...

【C++】异常exception

文章目录 1. C语言中传统的处理错误方法2. C中的异常3. 异常的使用3.1 异常的抛出和捕获3.2 异常的重新抛出3.3 异常安全3.4 异常规范 4. 自定义异常体系5. 异常的优缺点 &#x1f4dd; 个人主页 &#xff1a;超人不会飞)&#x1f4d1; 本文收录专栏&#xff1a;《C的修行之路》…...

2023-08-06力扣今日三题

链接&#xff1a; 剑指 Offer 59 - I. 滑动窗口的最大值 题意&#xff1a; 一个lg长度的数组&#xff0c;一个长度k的滑动窗口&#xff0c;求所有滑动窗口中的最大值 解&#xff1a; 优先队列存储存储下标&#xff0c;数字大的优先&#xff0c;每次判断最大的值是否在范围…...

kubeasz在线安装K8S集群

一、介绍 Kubeasz 是一个基于 Ansible 自动化工具&#xff0c;用于快速部署和管理 Kubernetes 集群的工具。它支持快速部署高可用的 Kubernetes 集群&#xff0c;支持容器化部署&#xff0c;可以方便地扩展集群规模&#xff0c;支持多租户&#xff0c;提供了强大的监控和日志分…...

Vue中实现Web端鼠标横向滑动和触控板滑动效果

系列文章目录 文章目录 系列文章目录前言一、鼠标横向滑动效果二、触控板滑动效果总结 前言 在Web端&#xff0c;我们经常需要实现鼠标横向滑动和触控板滑动的效果&#xff0c;以便在页面中展示横向滑动的内容。本文将介绍如何使用Vue和JavaScript来实现这两种效果&#xff0c…...

hdu5-Touhou Red Red Blue(贪心)

Problem - 7329 (hdu.edu.cn) 参考&#xff1a;题解 | #1006.Touhou Red Red Blue# 2023杭电暑期多校5 题解&#xff1a;&#xff08;贪心&#xff09; mp[R], mp[G], mp[P] 分别记录对应字母出现过多少次&#xff0c;没有AAA orABC 出现时不得分也不进行任何操作&#xff…...

【LeetCode 75】第二十三题(2352)相等行列对

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码运行结果&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目很简洁&#xff0c;就是要我们寻找行与列相同的对数。相同行与列不仅是要元素相同&#xff0c;还需要顺序也一样&#xff08…...

【云原生】详细学习Docker-Swarm部署搭建和基本使用

个人主页&#xff1a;征服bug-CSDN博客 kubernetes专栏&#xff1a;云原生_征服bug的博客-CSDN博客 目录 Docker-Swarm编排 1.概述 2.docker swarm优点 3.节点类型 4.服务和任务 5.路由网格 6.实践Docker swarm 1.概述 Docker Swarm 是 Docker 的集群管理工具。它将 Doc…...

awk相关知识点整理

1.awk的使用方法 1.1 语法 awk [options] script varvalue file(s) awk [options] -f scriptfile varvalue file1.2 命令常用选项 -F fs&#xff1a;fs指定输入分隔符&#xff0c;fs可以是字符串或正则表达式&#xff0c;如-F: -v varvalue&#xff1a;赋值一个用户定义变量…...

Mybatis案例-商品的增删改查

文章目录 1. aim2.环境准备3.查询3.1 查所有3.2 查看详情3.3 条件查询3.3.1 Mybatics如何接收参数&#xff1f;3.3.2 多条件查询3.3.3 动态条件查询3.3.4 单条件查询 4.添加主键返回 5.修改5.1 修改全部字段5.2 修改动态字段 6.删除6.1 删除1个6.2 批量删除 JDBC完成&#xff1…...

图像识别模型与训练策略

图像预处理 1.需要将图像Resize到相同大小输入到卷积网络中 2.翻转、裁剪、色彩偏移等操作 3.转化为Tensor数据格式 4.对RGB三种颜色通道进行标准化 data_transforms {train: transforms.Compose([transforms.Resize([96, 96]),transforms.RandomRotation(45),#随机旋转&…...

算法工程师-机器学习面试题总结(3)

FM模型 FM模型与逻辑回归相比有什么优缺点&#xff1f; FM&#xff08;因子分解机&#xff09;模型和逻辑回归是两种常见的预测建模方法&#xff0c;它们在一些方面有不同的优缺点。 FM模型的优点&#xff1a; 1. 能够捕获特征之间的交互作用&#xff1a;FM模型通过对特征向量…...

ROS2学习(五)进程内topic高效通信

对ROS2有一定了解后&#xff0c;我们会发现ROS2中节点和ROS1中节点的概率有很大的区别。在ROS1中节点是最小的进程单元。在ROS2中节点与进程和线程的概念完全区分开了。具体区别可以参考 ROS2学习(四)进程&#xff0c;线程与节点的关系。 在ROS2中同一个进程中可能存在多个节点…...

算法-最大数

给定一组非负整数 nums&#xff0c;重新排列每个数的顺序&#xff08;每个数不可拆分&#xff09;使之组成一个最大的整数。 注意&#xff1a;输出结果可能非常大&#xff0c;所以你需要返回一个字符串而不是整数。 输入&#xff1a;nums [10,2] 输出&#xff1a;"210&…...

Spark中使用RDD算子GroupBy做词频统计的方法

测试文件及环境 测试文件在本地D://tmp/spark.txt&#xff0c;Spark采用Local模式运行&#xff0c;Spark版本3.2.0&#xff0c;Scala版本2.12&#xff0c;集成idea开发环境。 hello world java world java java实验代码 import org.apache.spark.rdd.RDD import org.apache.…...

如何使用Kafka构建事件驱动的架构

事件驱动的架构(EDA)是一种软件设计模式&#xff0c;它关注事件的生成、检测和使用&#xff0c;以支持高效和可扩展的系统。在EDA中&#xff0c;事件是组件之间通信的主要手段&#xff0c;允许它们实时交互和响应更改。这种架构促进了松散耦合、可扩展性和响应性&#xff0c;使…...

ES6 解构赋值

解构赋值 解构赋值是一种在编程中常见且方便的语法特性&#xff0c;它可以让你从数组或对象中快速提取数据&#xff0c;并将数据赋值给变量。在许多编程语言中都有类似的特性。 在 JavaScript 中&#xff0c;解构赋值使得从数组或对象中提取数据变得简单。它可以用于数组和对…...

HTML5注册页面

分析 注册界面实际上是一个表格&#xff08;对齐&#xff09;&#xff0c;一行有两个单元格。 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevic…...

python中的JSON模块详解

简介 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式&#xff0c;它使得人们很容易的进行阅读和编写 同时也方便了机器进行解析和生成。适用于进行数据交互的场景&#xff0c;比如网站前台与后台之间的数据交互 网址 官方文档 json — JSON encoder and dec…...

Syncfusion Essential Edit for WPF Crack

Syncfusion Essential Edit for WPF Crack 在任何WPF应用程序中启用语法高亮显示。 Syncfusion Essential Edit for WPF是一款具有所有基本功能的编辑器&#xff0c;如文本编辑、剪切、复制和粘贴。它允许用户从各种文件格式打开文件并将其保存为各种文件格式。Syncfusion Esse…...

机器学习深度学习——卷积神经网络(LeNet)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——池化层 &#x1f4da;订阅专栏&#xff1a;机器学习&&深度学习 希望文章对你们有所帮助 卷积神…...

Pytorch Tutorial【Chapter 2. Autograd】

Pytorch Tutorial 文章目录 Pytorch TutorialChapter 2. Autograd1. Review Matrix Calculus1.1 Definition向量对向量求导1.2 Definition标量对向量求导1.3 Definition标量对矩阵求导 2.关于autograd的说明3. grad的计算3.1 Manual手动计算3.2 backward()自动计算 Reference C…...

Python第三方库国内镜像下载地址

Python第三方库国内镜像下载地址 一、清华大学二、中国科技大学三、安装方法 一、清华大学 https://pypi.tuna.tsinghua.edu.cn/simple 二、中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple 三、安装方法 例如 pyhook3 插件的安装方法&#xff0c;执行下面命令安装…...

从浏览器输入url到页面加载(七)服务端机器一般部署在哪里

前言 上一节&#xff0c;我们说到了CDN和路由器的关系&#xff0c;说到了公有地址&#xff0c;说到了通信线路服务&#xff0c;这一节跳过那些看不懂的深层知识&#xff0c;直接开始说web服务器。 1. 服务端机器为什么不部署在公司内部 记得在之前的一段时间里&#xff0c;公…...

Pytorch深度学习-----神经网络之Sequential的详细使用及实战详解

系列文章目录 PyTorch深度学习——Anaconda和PyTorch安装 Pytorch深度学习-----数据模块Dataset类 Pytorch深度学习------TensorBoard的使用 Pytorch深度学习------Torchvision中Transforms的使用&#xff08;ToTensor&#xff0c;Normalize&#xff0c;Resize &#xff0c;Co…...

安全基础 --- https详解 + 数组(js)

CIA三属性&#xff1a;完整性&#xff08;Confidentiality&#xff09;、保密性&#xff08;Integrity&#xff09;、可用性&#xff08;Availability&#xff09;&#xff0c;也称信息安全三要素。 https 核心技术&#xff1a;用非对称加密传输对称加密的密钥&#xff0c;然后…...

vue加载大量数据优化

在Vue中加载大量数据并形成列表时&#xff0c;可以通过以下方法来优化性能&#xff1a; 分页加载&#xff1a;不要一次性加载所有的数据&#xff0c;而是分批加载数据&#xff0c;每次只加载当前页需要显示的数据量。可以使用第三方库如vue-infinite-loading来实现无限滚动加载…...