【数据结构和算法】---栈和队列的互相实现

目录

  • 一、用栈实现队列
    • 1.1初始化队列
    • 1.2模拟入队列
    • 1.3模拟出队列
    • 1.4取模拟的队列头元素
    • 1.5判断队列是否为空
  • 二、用队列实现栈
    • 2.1初始化栈
    • 2.2模拟出栈
    • 2.3模拟入栈
    • 2.4取模拟的栈顶元素
    • 2.5判读栈是否为空

一、用栈实现队列

具体题目可以参考LeetCode232. 用栈实现队列
首先要想到的是,队列是一种先进先出的结构,而栈是一种先进后出的结构。依此我们可以定义两个栈结构来模拟先进先出,既然要定义两个栈,那么为了方便调用,我们可以将这两个栈结构定义在一个结构体中,如下:

typedef struct {ST st1;//栈1ST st2;//栈2
} MyQueue;

实现 MyQueue类:

  • void push(int x)将元素 x推到队列的末尾;
  • int pop()从队列的开头移除并返回元素;
  • int peek()返回队列开头的元素;
  • boolean empty()如果队列为空,返回 true;否则,返回 false

1.1初始化队列

我们定义的结构体在主函数外部,为了让每个函数都能用到,那么我们就必须要用malloc来动态开辟空间,这样此结构会被保存在静态区,每次函数调用时便不会销毁此变量,然后再将此结构体中的栈初始化

MyQueue* myQueueCreate() 
{MyQueue* queue = (MyQueue*)malloc(sizeof(MyQueue));//动态开辟结构体变量//注意初始化栈的参数为地址StackInit(&queue->st1);//初始化栈1StackInit(&queue->st2);//初始化栈2return queue;
}

1.2模拟入队列

我们可以将栈1作为存数据的栈,那么每次入队列操作就是进栈操作(StackPush(&obj->st1, x);)。

void myQueuePush(MyQueue* obj, int x) 
{assert(obj);StackPush(&obj->st1, x);
}

1.3模拟出队列

  1. 思路1:
    如果我们用栈1obj->st1来存放数据,在模拟出队列时我们首先要断言栈1不为空,那么当栈1不为空且我们需要出队列头元素时。此时就需要栈2obj->st2来暂存数据,即我们将栈1除栈底的全部元素都出栈并入栈到栈2obj->st2,然后再出栈1最后的元素并返回,这样就模拟了先入先出性质。还需要注意的是在返回最后一个元素前还需要再将所有数据从栈2再入到栈1。逻辑如下:

在这里插入图片描述

  1. 思路2:
    栈1用来存数据,栈2用来出数据。 那么为什么栈2的元素可以直接出呢?当我们需要模拟出队列时,我们可以先将栈1中所以元素出栈并入栈到栈2,这样一来栈2中的top就相当于队列头元素。每次从栈2中出元素时要先判断栈2中是否有元素,若没有,就将栈1中的元素出栈并入栈到栈2中。大致逻辑如下:

在这里插入图片描述

与思路一相比较,思路二栈2无需重新入栈1,还可继续模拟出队列。只能说两种思路各有好处,下列代码实现使用的是思路一:

int myQueuePop(MyQueue* obj) 
{assert(obj);assert(StackSize(&obj->st1) != 0);//栈1不为空ST* empty = &obj->st2;//栈2为空ST* noempty = &obj->st1;//栈1不为空//将栈1除栈底的所有元素出栈并入栈到栈2while(StackSize(noempty) > 1){StackPush(empty,StackTop(noempty));StackPop(noempty);}//找到队头int ret = StackTop(noempty);StackPop(noempty);//重新入栈1while(StackSize(empty) > 0){StackPush(noempty,StackTop(empty));StackPop(empty);}return ret;
}

1.4取模拟的队列头元素

此函数实现与1.3模拟出队列方法相似,就不多介绍了,如下:

int myQueuePeek(MyQueue* obj)
{assert(obj);ST* empty = &obj->st2;ST* noempty = &obj->st1;//将栈1除栈底的所有元素出栈并入栈到栈2while(StackSize(noempty) > 1){StackPush(empty,StackTop(noempty));StackPop(noempty);}//找到队头int ret = StackTop(noempty);StackPush(empty,ret);StackPop(noempty);//重新入栈1while(StackSize(empty) > 0){StackPush(noempty,StackTop(empty));StackPop(empty);}return ret;
}

1.5判断队列是否为空

依据上面思路,因为栈1是用来存数据的,所以当栈1为空时就代表我们模拟的队列为空。

bool myQueueEmpty(MyQueue* obj) 
{assert(obj);return StackEmpty(&obj->st1);
}

二、用队列实现栈

具体题目可以参考LeetCode225. 用队列实现栈
与用栈实现队列相似,我们同样需要两个队列来模拟实现栈,且关键在于还原队列先入先出的性质,依此性质来实现函数。既然这样我们可以如下定义结构体:

typedef struct 
{Queue* q1;//队列1Queue* q2;//队列2
} MyStack;

我们可以看到与模拟队列不同的是,模拟栈的结构体中存放的是两个结构体指针,这与队列的实现方法有关。因为我们用的队列是用链表实现的,所以其每个节点都是组成队列的一部分,且我们应该通过指针将他们一个个都连接起来(即通过指针来寻找节点)。
至于用栈实现队列问题中的结构体我们存放的是两个关于栈的结构体,是因为我们所使用的栈使用数组来实现的,这样一来我们操作的就是栈结构体中某一个元素(即动态开辟的数组)。当然在我们也可以放两个栈结构体指针,只不过在下面初始化队列时(myQueueCreate() )我们需要额外malloc动态开辟栈结构大小的空间,然后将指针指向该空间的地址。
实现 MyStack类:

  • void push(int x)将元素 x压入栈顶;
  • int pop()移除并返回栈顶元素;
  • int top()返回栈顶元素;
  • boolean empty()如果栈是空的,返回 true;否则,返回 false

2.1初始化栈

malloc()动态开辟栈结构体没什么问题,与模拟队列相似。但为什么还要给结构体中的两个队列结构体指针动态开辟空间呢?这样不就违背了我们上面探讨的问题了吗?其实不然,这里的两个结构体指针事实上指向的是存放队列头指针和尾指针的结构体,如下:

typedef struct Queue
{QNode* phead;//队列头指针QNode* ptail;//队列尾指针int size;//长度
}Queue;

这样一来,基本每个函数都需要用到此结构体,那么我们就必须malloc开辟来增加作用域和生命周期。 最后再初始化这两个存放头/尾指针的结构体,并返回用来模拟栈的结构体地址。

MyStack* myStackCreate() 
{MyStack* pst = (MyStack*)malloc(sizeof(MyStack));pst->q1 = (Queue*)malloc(sizeof(Queue));pst->q2 = (Queue*)malloc(sizeof(Queue));QueueInit(pst->q1);QueueInit(pst->q2);return pst;
}

2.2模拟出栈

与模拟出队列不同的是,这里用来模拟出栈的两个队列都可以用来出栈和入栈,具体方法如下:
为了还原栈先入后出的性质,我们可以先找到不为空的队列(因为两个队列都有可能有数据,但不同时有),然后将有数据的队列(noempty)除队尾的一个节点全都出队列并入队列到无数据的队列(empty,这样一来就找到了尾节点(模拟的栈顶)。还需要注意的是,此时我们无需再将数据重新入到noempty 逻辑大致如下:

在这里插入图片描述

int myStackPop(MyStack* obj) 
{//先假设队列1为空Queue* empty = obj->q1;Queue* noempty = obj->q2;//纠正if(QueueEmpty(obj->q2)){empty = obj->q2;noempty = obj->q1;}//noempty出,并入到emptywhile(QueueSize(noempty) > 1){int cmp = QueueFront(noempty);QueuePop(noempty);QueuePush(empty, cmp);}//取到模拟的栈顶元素int ret = QueueFront(noempty);QueuePop(noempty);return ret;
}

2.3模拟入栈

依据上面的方法,我们是要将数据入到不为空的队列,简单的if语句便可完成筛选。

void myStackPush(MyStack* obj, int x) 
{assert(obj);if(!QueueEmpty(obj->q1)){QueuePush(obj->q1, x);}else{QueuePush(obj->q2, x);}
}

2.4取模拟的栈顶元素

同样我们需要找到不为空的那个队列,且事实上队列尾指针指向的那个节点就是模拟的栈的栈顶,我们只需返回此元素即可。

int myStackTop(MyStack* obj) 
{assert(obj);//找不为空的队列if(!QueueEmpty(obj->q1))return QueueBack(obj->q1);elsereturn QueueBack(obj->q2);
}

2.5判读栈是否为空

当两个队列都没有数据时,那么模拟的栈就是空栈。

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

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

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

相关文章

SpringMVC:整合 SSM 下篇

文章目录 SpringMVC - 05整合 SSM 下篇一、设计页面1. 首页:index.jsp2. 展示书页面:showBooks.jsp3. 增加书页面:addBook.jsp4. 修改书页面:updateBook.jsp5. 总结 二、控制层1. 查询全部书2. 增加书3. 修改书4. 删除书5. 搜索书…

SpringMVC系列之技术点定向爆破二

SpringMVC的运行流程 客户端发送请求 tomcat接收对应的请求 SpringMVC的核心调度器DispatcherServlet接收到所有请求 请求地址与RequestMapping注解进行匹配,定位到具体的类和具体的处理方法(封装在Handler中) 核心调度器找到Handler后交…

成功案例分享:物业管理小程序如何助力打造智慧社区

随着科技的进步和互联网的普及,数字化转型已经渗透到各个行业,包括物业管理。借助小程序这一轻量级应用,物业管理可以实现线上线下服务的无缝对接,提升服务质量,优化用户体验。本文将详细介绍如何通过乔拓云网设计小程…

LeetCode刷题--- 目标和

个人主页:元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 http://t.csdnimg.cn/yUl2I 【C】 http://t.csdnimg.cn/6AbpV 数据结构与算法 http://t.csdnimg.cn/hKh2l 前言:这个专栏主要讲述递归递归、搜…

基于SSM的剧本杀预约系统(有报告)。Javaee项目。ssm项目。

演示视频: 基于SSM的剧本杀预约系统(有报告)。Javaee项目。ssm项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构,通过Spring Sp…

easyrecovery数据恢复软件15安装下载免注册版本下载

说起数据恢复软件,相信没有小伙伴不知道easyrecovery这个软件吧,该软件具有快捷、高效、便捷的特点,且提供的功能也非常全面,不仅可以恢复各样被删除的文件、视频、图片等,还可以支持SD卡数据恢复,TF卡等各…

系列一、MQ简介

一、MQ简介 1.1、概述 MQ(Message Queue),是一种提供消息队列服务的中间件,也称为消息中间件,是一套提供了消息(消息即数据,一般消息的体量不会很大)生产、存储、消费全过程的API软…

第11章 GUI Page421~422 步骤六 支持文字

运行效果: 关键代码: 新增头文件: //item_text.hpp #ifndef ITEM_TEXT_HPP_INCLUDED #define ITEM_TEXT_HPP_INCLUDED #include "item_i.hpp"class TextItem : public IItem { public:TextItem(): _startPosition(0, 0), _endPos…

【华为鸿蒙系统学习】- 如何利用鸿蒙系统进行App项目开发|自学篇

🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 💫个人格言:"没有罗马,那就自己创造罗马~" 目录 创建鸿蒙第一个App项目 项目创建 工程目录区 预览区 运行Hello World 基本工程目录 ws:工…

关于“Python”的核心知识点整理大全36

目录 13.4.4 向下移动外星人群并改变移动方向 game_functions.py alien_invasion.py 13.5 射杀外星人 13.5.1 检测子弹与外星人的碰撞 game_functions.py alien_invasion.py 13.5.2 为测试创建大子弹 13.5.3 生成新的外星人群 game_functions.py alien_invasion.py …

Zookeeper-应用实战

Zookeeper Java客户端实战 ZooKeeper应用的开发主要通过Java客户端API去连接和操作ZooKeeper集群。 ZooKeeper官方的Java客户端API。 第三方的Java客户端API,比如Curator。 ZooKeeper官方的客户端API提供了基本的操作:创建会话、创建节点、读取节点、更新数据、…

7ADC模数转换器

一.模数转换原理 ADC模拟-数字转换器可以将引脚上连续变化的模拟电压转换成内存中存储的数字变量,建立模拟电路到数字电路的桥梁。另外一种是DAC既是与前面相反,如PWM波,由于PWM电路简单且没有额外的功率损耗,更适用于惯性系统的…

损失函数,代价函数,梯度,优化器,学习率,学习率调度器

这些是机器学习中的概念。把这些概念迁移到CV领域要进行一定的抽象。 首先损失,损失是一组参数拟合出来的样本的预测值和样本的真实值之间的差异,损失是用来度量这种差异的,根据不同的拟合权重参数全局有一个对应的损失值,损失后…

随机问卷调查数据的处理(uniapp)

需求:问卷调查 1.返回的数据中包含单选、多选、多项文本框、单文本框、图片上传 2.需要对必填的选项进行校验 3.非必填的多项文本框内容 如果不填写 不提交 表单数据格式 res{"code": 0,"msg": null,"data": [{"executeDay&…

两个图片完美融合 泊松编辑

一、效果惊人 二、步骤 下载安装 https://github.com/Trinkle23897/Fast-Poisson-Image-Editing.git 执行 test 目录下的 python data.py下载数据 执行测试,可以看到效果了 $ fpie -s test1_src.jpg -m test1_mask.jpg -t test1_tgt.jpg -o result1.jpg -h1 -…

JNI学习(二)

静态注册 接着上篇博客学习 JNI函数 JNIEXPORT void JNICALL Java_com_example_jnidemo_TextDemo_setText(JNIEnv *env, jobject this, jstring string){ __android_log_print(ANDROID_LOG_ERROR, "test", "invoke set from C\n");char* str (char*)(*e…

【Unity】入门

文章目录 概述常用组件各类文件基础知识创建工程工程目录介绍五个窗口面板创建代码和场景 脚本与编程鼠标的输入键盘的输入代码来操作组件获取物体API资源的使用API定时调用与线程向量的基本运算预制体与实例 物理系统与组件案例实操作快捷键来源 Unity已广泛运用到各个领域&am…

如何在Windows上搭建WebDAV服务并通过内网穿透实现公网访问

文章目录 前言1. 安装IIS必要WebDav组件2. 客户端测试3. 使用cpolar内网穿透,将WebDav服务暴露在公网3.1 安装cpolar内网穿透3.2 配置WebDav公网访问地址 4. 映射本地盘符访问 前言 在Windows上如何搭建WebDav,并且结合cpolar的内网穿透工具实现在公网访…

结构型模式 | 适配器模式

一、适配器模式 1、原理 适配器模式(Adapter),将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。适配器模式主要分为三类:类适配器模式、对象适配器模式、接口…

【ARM Cortex-M 系列 5 -- RT-Thread renesas/ra4m2-eco 移植编译篇】

文章目录 RT-Thread 移植编译篇编译os.environ 使用示例os.putenv使用示例python from 后指定路径 编译问题_POSIX_C_SOURCE 介绍编译结果 RT-Thread 移植编译篇 本文以瑞萨的ra4m2-eco 为例介绍如何下载rt-thread 及编译的设置。 RT-Thread 代码下载: git clone …