初级数据结构——栈与队列的互相实现

目录

  • 前言
  • 一、用栈实现队列
    • 操作:
    • c++代码模版
    • 经典例题
  • 二、用队列实现栈
    • 操作:
    • c++代码模版
    • 经典例题
  • 三、总结
  • 四、结语

前言

通过我之前的作品已经初步理解了栈和队列的数据结构,这期我们来学习如何实现这两个数据结构的互相转换。在计算机科学中,栈(Stack)和队列(Queue)是两种常见的数据结构,它们具有不同的操作特性和应用场景。栈遵循后进先出(LIFO, Last In First Out)的原则,而队列遵循先进先出(FIFO, First In First Out)的原则。尽管它们有不同的特性,但我们可以利用其中一种数据结构来实现另一种数据结构。

在这里插入图片描述

一、用栈实现队列

操作:

要使用栈来实现队列,我们需要两个栈:一个用于处理入队操作(stack_in),另一个用于处理出队操作(stack_out)。

入队(Enqueue):
直接将元素压入 stack_in。

出队(Dequeue):
如果 stack_out 为空,则将 stack_in 中的所有元素逐个弹出并压入 stack_out(这样原来 stack_in 中的栈底元素就移动到了 stack_out 的栈顶)。然后从 stack_out 弹出栈顶元素。

检查队列是否为空(IsEmpty):
当 stack_in 和 stack_out 都为空时,队列为空。

查看队列的头部元素(Peek):
类似于出队操作,但如果 stack_out 为空,则将 stack_in 中的所有元素移动到 stack_out,然后返回 stack_out 的栈顶元素(但不弹出)。

c++代码模版

#include<iostream>
#include<exception>
using namespace std;template<typename T>//定制栈里面的元素,就像vector一样
class Stack {
private:int size;//既为栈元素个数又为栈顶位置int capacity;T* data;void resize();
public:Stack() :data(new T[capacity]), size(0), capacity(10) {}//构造函数,申请类型为T容量为capacity的内存空间,相当于数组~Stack();void push(T x);T top() const;T pop();int getSize() const;bool empty() const;
};template<typename T>
void Stack<T>::resize() {//顺序栈扩容int newCapacity = 2 * capacity;T* newData = new T[newCapacity];for (int i = 0; i < size; i++) {newData[i] = data[i];}delete[]data;data = newData;capacity = newCapacity;
}template<typename T>
Stack<T>::~Stack() {delete[]data;
}template<typename T>
void Stack<T>::push(T x) {if (size == capacity) {resize();}data[size++] = x;
}template<typename T>
T Stack<T>::top() const {if (!size) {throw std::underflow_error("Stack is empty");//如果栈为空即为非法状态,抛出异常}return data[size - 1];//注意栈元素序号从零开始
}template<typename T>
T Stack<T>::pop() {if (!size) {throw std::underflow_error("Stack is empty");}return data[--size];
}template<typename T>
int Stack<T>::getSize() const {return size;
}template<typename T>
bool Stack<T>::empty() const {return size == 0;
}class MyQueue {
private:Stack<int> s1;//s1作为辅助栈Stack<int> s2;
public:MyQueue(){}void push(int x) {s1.push(x);//队列插入元素,就是把元素插入s1中}int pop() {if (s2.empty()) {//队列出队操作,就是将s1中谈栈入栈到s2中,队首就是s2的栈顶while (!s1.empty()) {s2.push(s1.pop());}}return s2.pop();}int peek() {//去队首函数if (s2.empty()) {while (!s1.empty()) {s2.push(s1.pop());}}return s2.top();}bool empty() {//队列判空函数return s1.empty() && s2.empty();}
};int main() {MyQueue m;for (int i = 0; i < 5; i++) {m.push(i);}cout << m.peek() << endl;return 0;
}

经典例题

面试题 03.04. 化栈为队
(蓝色字体可以点进去看原题)

代码题解

template<typename T>//定制栈里面的元素,就像vector一样
class Stack {
private:int size;//既为栈元素个数又为栈顶位置int capacity;T* data;void resize();
public:Stack() :data(new T[capacity]), size(0), capacity(10) {}//构造函数,申请类型为T容量为capacity的内存空间,相当于数组~Stack();void push(T x);T top() const;T pop();int getSize() const;bool empty() const;
};template<typename T>
void Stack<T>::resize() {//顺序栈扩容int newCapacity = 2 * capacity;T* newData = new T[newCapacity];for (int i = 0; i < size; i++) {newData[i] = data[i];}delete[]data;data = newData;capacity = newCapacity;
}template<typename T>
Stack<T>::~Stack() {delete[]data;
}template<typename T>
void Stack<T>::push(T x) {if (size == capacity) {resize();}data[size++] = x;
}template<typename T>
T Stack<T>::top() const {if (!size) {throw std::underflow_error("Stack is empty");//如果栈为空即为非法状态,抛出异常}return data[size - 1];//注意栈元素序号从零开始
}template<typename T>
T Stack<T>::pop() {if (!size) {throw std::underflow_error("Stack is empty");}return data[--size];
}template<typename T>
int Stack<T>::getSize() const {return size;
}template<typename T>
bool Stack<T>::empty() const {return size == 0;
}class MyQueue {
private:Stack<int> s1;//s1作为辅助栈Stack<int> s2;
public:MyQueue(){}void push(int x) {s1.push(x);//队列插入元素,就是把元素插入s1中}int pop() {if (s2.empty()) {//队列出队操作,就是将s1中谈栈入栈到s2中,队首就是s2的栈顶while (!s1.empty()) {s2.push(s1.pop());}}return s2.pop();}int peek() {//去队首函数if (s2.empty()) {while (!s1.empty()) {s2.push(s1.pop());}}return s2.top();}bool empty() {//队列判空函数return s1.empty() && s2.empty();}
};

二、用队列实现栈

要使用队列来实现栈,我们可以使用一个队列(queue)和两个辅助变量:size 用于跟踪队列中的元素数量,main_queue 和 temp_queue 用于操作。

操作:

入栈(Push):
将新元素添加到 temp_queue。
将 main_queue 中的所有元素依次出队并重新入队到 temp_queue(这样原来 main_queue 中的最后元素就到了 temp_queue 的前面)。交换 main_queue 和 temp_queue 的引用。

出栈(Pop):
从 main_queue 出队元素(因为 main_queue 的第一个元素就是栈顶元素)。

检查栈是否为空(IsEmpty):
当 main_queue 为空时,栈为空。

查看栈顶元素(Peek):
返回 main_queue 的第一个元素(但不出队)。

c++代码模版

#include<iostream>
#include<exception>
using namespace std;template<typename T>
class Queue {
private:int front;int rear;int capacity;T* data;void resize();
public:Queue() :data(new T[capacity]), front(0), rear(0), capacity(10) {}~Queue();void Enqueue(T x);T Dequeue();T getFront();int size();bool empty();
};template<typename T>
void Queue<T>::resize() {int newCapacity = capacity * 2;T* newData = new T[newCapacity];for (int i = front; i < rear; i++) {newData[i] = data[i];}delete[] data;data = newData;capacity = newCapacity;
}template<typename T>
Queue<T>::~Queue() {delete[]data;
}template<typename T>
void Queue<T>::Enqueue(T x) {if (rear == capacity) resize();data[rear++] = x;
}template<typename T>
T Queue<T>::Dequeue() {if (front == rear) {throw std::underflow_error("Queue is empty!");}return data[front++];
}template<typename T>
T Queue<T>::getFront() {if (front == rear) {throw std::underflow_error("Queue is empty!");}return data[front];
}template<typename T>
int Queue<T>::size() {return rear - front;
}template<typename T>
bool Queue<T>::empty() {return size() == 0;
}class MyStack {
private:Queue<int>q1;//辅助队列Queue<int>q2;
public:void push(int x) {q1.Enqueue(x);}int pop() {while (q1.size() > 1) {q2.Enqueue(q1.Dequeue());}int ret = q1.Dequeue();while (!q2.empty()) {q1.Enqueue(q2.Dequeue());}return ret;}int top() {while (q1.size() > 1) {//把q1除队尾以为元素存入q2,剩下的元素就是栈顶q2.Enqueue(q1.Dequeue());}int ret = q1.Dequeue();//去除栈顶以后记得将该值放进q2q2.Enqueue(ret);while (!q2.empty()) {q1.Enqueue(q2.Dequeue());}return ret;}bool empty() {return q1.empty();}
};int main() {MyStack s;for (int i = 0; i < 5; i++) {s.push(i);}cout << s.top() << endl;int x = s.pop();cout << x << endl;cout << s.empty() << endl;return 0;
}

经典例题

225. 用队列实现栈

代码题解

template<typename T>
class Queue {
private:int front;int rear;int capacity;T* data;void resize();
public:Queue() :data(new T[capacity]), front(0), rear(0), capacity(10) {}~Queue();void Enqueue(T x);T Dequeue();T getFront();int size();bool empty();
};template<typename T>
void Queue<T>::resize() {int newCapacity = capacity * 2;T* newData = new T[newCapacity];for (int i = front; i < rear; i++) {newData[i] = data[i];}delete[] data;data = newData;capacity = newCapacity;
}template<typename T>
Queue<T>::~Queue() {delete[]data;
}template<typename T>
void Queue<T>::Enqueue(T x) {if (rear == capacity) resize();data[rear++] = x;
}template<typename T>
T Queue<T>::Dequeue() {if (front == rear) {throw std::underflow_error("Queue is empty!");}return data[front++];
}template<typename T>
T Queue<T>::getFront() {if (front == rear) {throw std::underflow_error("Queue is empty!");}return data[front];
}template<typename T>
int Queue<T>::size() {return rear - front;
}template<typename T>
bool Queue<T>::empty() {return size() == 0;
}class MyStack {
private:Queue<int>q1;//辅助队列Queue<int>q2;
public:void push(int x) {q1.Enqueue(x);}int pop() {while (q1.size() > 1) {q2.Enqueue(q1.Dequeue());}int ret = q1.Dequeue();while (!q2.empty()) {q1.Enqueue(q2.Dequeue());}return ret;}int top() {while (q1.size() > 1) {//把q1除队尾以为元素存入q2,剩下的元素就是栈顶q2.Enqueue(q1.Dequeue());}int ret = q1.Dequeue();//去除栈顶以后记得将该值放进q2q2.Enqueue(ret);while (!q2.empty()) {q1.Enqueue(q2.Dequeue());}return ret;}bool empty() {return q1.empty();}
};

三、总结

通过以上方法,我们可以使用栈来实现队列,或使用队列来实现栈。这些实现虽然效率不如直接使用相应的数据结构(因为涉及额外的操作),但它们展示了数据结构之间的转换和灵活性。

四、结语

通过本次学习相信大家对栈和队列这两个数据结构有更深刻理解了,希望大家多刷题巩固知识点,那么下期我们一起学习初级数据结构——串。

在这里插入图片描述
想看更多内容可以关注我,看我作品,关注我让我们一起学习编程,希望大家能点赞关注支持一下,让我有持续更新的动力,谢谢大家

在这里插入图片描述

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

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

相关文章

Qt的一个基本用户登录界面编写|| 从0搭建QT的信号与槽的应用案例 ||Qt样式表的应用

目录 1.新建1个qt项目&#xff0c;基类选中QWidget 2.ui文件布局 3.头文件 3.1 explicit的作用 具体解释 示例 4.cpp源文件 5.信号与槽的应用 6.qt实现效果 7.qt样式表的应用 1.新建1个qt项目&#xff0c;基类选中QWidget 2.ui文件布局 3.头文件 #ifndef WIDADMINLO…

【Apache Paimon】-- 2 -- 核心特性 (0.9.0)

目录 1、实时更新 1.1、实时大批量更新 1.2、支持定义合并引擎 1.3、支持定义更新日志生成器 2、海量数据追加处理 2.1、append table 2.2、快速查询 3、数据湖功能&#xff08;类比&#xff1a;hudi、iceberg、delta&#xff09; 3.1、支持 ACID 事务 3.2、支持 Time…

webpack配置

4-3vue-loader测试_哔哩哔哩_bilibili 一.新建文件夹vue_todo&#xff0c;vscode打开 二.ctrl打开终端&#xff0c;输入npm init -y&#xff0c;快速生成一个默认的package.json文件 之后左边出现项目初始化文件package.json 三.接下来需要webpack完成打包&#xff0c;所以安装…

5.STM32之通信接口《精讲》之USART通信---实验串口接收程序

根据上节&#xff0c;我们一已经完成了串口发送程序的代码&#xff0c;并且深入的解析探索了串口的原理&#xff0c;接下来&#xff0c;Whappy小编将带领大家进入串口接收程序的探索与实验&#xff0c;并将结合上一节串口发送一起来完成串口的发送和接收实验。 上来两张图 上图…

leetcode 扫描线专题 06-leetcode.836 rectangle-overlap 力扣.836 矩形重叠

题目 矩形以列表 [x1, y1, x2, y2] 的形式表示&#xff0c;其中 (x1, y1) 为左下角的坐标&#xff0c;(x2, y2) 是右上角的坐标。 矩形的上下边平行于 x 轴&#xff0c;左右边平行于 y 轴。 如果相交的面积为 正 &#xff0c;则称两矩形重叠。 需要明确的是&#xff0c;只在…

ASP.NET MVC宠物商城系统

该系统采用B/S架构&#xff0c;使用C#编程语言进行开发&#xff0c;以ASP.NET MVC框架为基础&#xff0c;以Visual Studio 2019为开发工具&#xff0c;数据库采用SQL Server进行保存数据。系统主要功能包括登录注册、宠物展示、个人中心、我的订单、购物车、用户管理、宠物类别…

最优化方法_罚函数法例题

1 外点罚函数 算法1 外点罚函数法 给定初点&#xff0c;初始罚因子,放大系数&#xff0c;允许误差&#xff0c;置k1。以为初始点&#xff0c;求解无约束问题得最优解。如果,则停止计算&#xff0c;为约束问题的近似最优解&#xff1b;否 则&#xff0c;增大罚因子&#xff0c;令…

python调用MySql保姆级教程(包会的)

目录 一、下载MySql 二、安装MySql 三、验证MySql是否OK 1、MySQL控制台验证 2、命令提示符cmd窗口验证 四、Python调用MySql 4.1 安装pysql 4.2 使用pysql 4.2.1、连接数据库服务器并且创建数据库和表 4.2.2 、将人脸识别考勤系统识别到的数据自动填入到数据库的表单中…

【鸿蒙生态崛起,开发者有哪些机遇与挑战?】HarmonyOS NEXT 引领数字化未来

文章目录 前言一、HarmonyOS NEXT 特点与升级二、全面突破操作系统核心技术三、鸿蒙生态全面守护用户隐私四、鸿蒙生态的崛起与开发者机遇五、全新鸿蒙生态引领数字化未来小结 前言 鸿蒙系统不断发展&#xff0c;有与安卓、iOS 形成三足鼎立之势&#xff0c;且其在智能手机、智…

ssh无法连接Ubuntu

试了多次ssh都无法连接&#xff0c;明明可以上网 网卡、防火墙、端口都没有问题&#xff0c;就是连接不上 结果是这个版本Ubuntu镜像默认没有安装ssh服务 安装SSH服务&#xff1a;apt-get install openssh-server 开启SSH服务&#xff1a;/etc/init.d/ssh start 就可以连接…

基于Java Springboot外卖平台系统

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数…

vue2动态导出多级表头表格

需求&#xff1a;导出多级表格&#xff0c;如下&#xff0c;每个人名对应的是不同的城市金钱和年龄&#xff0c;日期占俩行&#xff0c;需要根据数据进行动态展示 1.效果 2.关键代码讲解 2.1数据源 2.2所需插件 npm install xlsx 2.3关键代码 创建name组和date组&#xff0c…

散户持股增厚工具:智能T0算法交易

最近市场很多都说牛市&#xff0c;但是大多数朋友怎么来的又怎么吐出去了。这会儿我们用T0的智能算法交易又可以增厚我们的持仓收益。简单来说&#xff0c;就是基于用户原有的股票持仓&#xff0c;针对同一标的&#xff0c;配合智能T0算法&#xff0c;每天全自动操作&#xff0…

独立开发:一人公司模式下副业产品的全流程

在数字经济的浪潮下&#xff0c;越来越多的开发者选择成为自由职业者或创立一人公司&#xff0c;通过副业产品开发实现个人价值与经济收益的双重提升。本文将围绕一人公司模式下副业产品的设计、开发、运营及变现落地全流程&#xff0c;提供一套实战指南&#xff0c;帮助有志于…

SD模型微调之Textual Inversion和Embedding fine-tuning

​ &#x1f33a;系列文章推荐&#x1f33a; 扩散模型系列文章正在持续的更新&#xff0c;更新节奏如下&#xff0c;先更新SD模型讲解&#xff0c;再更新相关的微调方法文章&#xff0c;敬请期待&#xff01;&#xff01;&#xff01;&#xff08;本文及其之前的文章均已更新&a…

【Vue笔记】基于vue3 + element-plus + el-dialog封装一个自定义的dialog弹出窗口组件

这篇文章,介绍一下如何使用vue3+element-plus中的el-dialog组件,自己封装一个通用的弹出窗口组件。运行效果如下所示: 目录 1.1、父子组件通信 1.2、自定义VDialog组件(【v-model】模式) 1.2.1、编写VDialog组件代码 1.2.2、使用VDialog组件 1.2.3、运行效果 1.3、自…

Spring Cloud Alibaba [Gateway]网关。

1 简介 网关作为流量的入口&#xff0c;常用功能包括路由转发、权限校验、限流控制等。而springcloudgateway 作为SpringCloud 官方推出的第二代网关框架&#xff0c;取代了Zuul网关。 1.1 SpringCloudGateway特点: &#xff08;1&#xff09;基于Spring5&#xff0c;支持响应…

不完全微分PID控制算法

不完全微分PID控制算法是一种改进的PID控制方法&#xff0c;主要针对PID控制中的微分环节对高频噪声敏感的问题。通过对微分项进行优化和改造&#xff0c;减少其对噪声的放大作用&#xff0c;同时保留对系统动态变化的响应能力。 不完全微分PID控制原理 不完全微分的核心思想是…

DataOps for LLM 的数据工程技术架构实践

导读 在 LLM 蓬勃发展的今天&#xff0c;数据工程已成为支持大规模 AI 模型训练的基石。DataOps 作为数据工程的重要方法论&#xff0c;通过优化数据集成、转换和自动化运维&#xff0c;加速数据到模型的闭环流程。本文聚焦新一代数据 & AI 集成工具- Apache SeaTunnel 在…

go-zero(七) RPC服务和ETCD

go-zero 实现 RPC 服务 在实际的开发中&#xff0c;我们是通过RPC来传递数据的&#xff0c;下面我将通过一个简单的示例&#xff0c;说明如何使用go-zero框架和 Protocol Buffers 定义 RPC 服务。 一、生成 RPC项目 在这个教程中&#xff0c;我们根据user.api文件&#xff0…