Leetcode每日一题——“用队列实现栈”

news2025/1/18 12:03:53

各位CSDN的uu们你们好呀,好久没有更新本专栏啦,甚是想念!!!今天,小雅兰的学习内容是用队列实现栈,下面,让我们进入Leetcode的世界吧!!!


 

这是小雅兰写过的栈和队列的文章,有兴趣的可以看看:

栈——“数据结构与算法”_认真学习的小雅兰.的博客-CSDN博客 

队列——“数据结构与算法”_认真学习的小雅兰.的博客-CSDN博客


如图所示: 

这里相当于 栈中的Push1 2 3 4这四个数据

可以使用两个队列进行导数据

 

如果还想再导出一个数据,那么还是同样的方法:

 

 

这里相当于栈中两次连续的Pop 

如果还想Push5 6这两个数据,那么:

然后再Pop,还是一样的,这次Pop一次,Pop出的就是6啦

 

好的,那么我们的基本思路就是这样的啦,下面,我们开始用代码实现它吧


首先,我们用的是C语言的话,还要自己实现一个队列,直接上代码:

typedef int QDataType;
// 链式结构:表示队列 
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QueueNode;
// 队列的结构 
typedef struct Queue
{
	QueueNode* phead;//头指针
	QueueNode* ptail;//尾指针
	int size;
}Queue;
// 初始化队列
void QueueInit(Queue* pq);

// 销毁队列 
void QueueDestroy(Queue* pq);

// 队尾入队列 
void QueuePush(Queue* pq, QDataType x);

// 队头出队列 
void QueuePop(Queue* pq);

// 获取队列头部元素 
QDataType QueueFront(Queue* pq);

// 获取队列队尾元素 
QDataType QueueBack(Queue* pq);

// 获取队列中有效元素个数 
int QueueSize(Queue* pq);

// 检测队列是否为空
bool QueueEmpty(Queue* pq);

// 初始化队列
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

// 销毁队列 
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QueueNode* cur = pq->phead;
	while (cur != NULL)
	{
		QueueNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

// 队尾入队列 
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;
	//是空队列的情况
	if (pq->ptail == NULL)
	{
		assert(pq->phead == NULL);
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}

// 检测队列是否为空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->phead == NULL && pq->ptail == NULL;
}

// 队头出队列 
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	//1.一个结点
	//2.多个结点
	if (pq->phead->next == NULL)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else
	{
		//相当于头删
		QueueNode* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
	pq->size--;
}

// 获取队列头部元素 
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->phead->data;
}

// 获取队列队尾元素 
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->ptail->data;
}

// 获取队列中有效元素个数 
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

 剩余的功能就按照Leetcode上面给定的来:

typedef struct {
    Queue q1;
    Queue q2;
} MyStack;

这是一个匿名结构体,把这个匿名结构体typedef成MyStack

MyStack* myStackCreate() {
  MyStack obj;
  return &obj;
}

这个程序能不能这样写呢?

答案当然是否定的。

MyStack是一个局部结构体变量,出了作用域,它就销毁了

它是存在栈帧里面的,栈帧已经销毁了

所以这就是一个野指针

正确的写法:

MyStack* myStackCreate() {
    MyStack* obj=(MyStack*)malloc(sizeof(MyStack));
    if(obj==NULL)
    {
        perror("malloc fail");
        return NULL;
    }
    //这里->的优先级更高,取地址是对obj->q1和obj->q2取地址
    QueueInit(&obj->q1);
    QueueInit(&obj->q2);
    return obj;
}

这里->的优先级更高,取地址是对obj->q1和obj->q2取地址

有的人可能会觉得在QueueInit里面取地址比较麻烦,那么,就衍生出了另外一种写法:

typedef struct {
    Queue* q1;
    Queue* q2;
} MyStack;
MyStack* myStackCreate() {
    MyStack* obj=(MyStack*)malloc(sizeof(MyStack));
    if(obj==NULL)
    {
        perror("malloc fail");
        return NULL;
    }
    //两种写法
    obj->q1=(Queue*)malloc(sizeof(Queue));
    obj->q2=(Queue*)malloc(sizeof(Queue));
    QueueInit(obj->q1);
    QueueInit(obj->q2);
    return obj;
}

 

void myStackPush(MyStack* obj, int x) {
    //q1不为空
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1,x);
    }
    else
    {
        QueuePush(&obj->q2,x);
    }
}

删除数据:

由于不知道数据在q1还是在q2

int myStackPop(MyStack* obj) {
    //由于不知道数据是在q1还是在q2
    //q1为空 q2不为空
    //这是一种假设 假设有可能错误
    Queue* pEmptyQ=&obj->q1;
    Queue* pNonEmptyQ=&obj->q2;
    //q1不为空
    if(!QueueEmpty(&obj->q1))
    {
        //q2为空 q1不为空
        pEmptyQ=&obj->q2;
        pNonEmptyQ=&obj->q1;
    }
    //导数据
    while(QueueSize(pNonEmptyQ)>1)
    {
        //非空里面的数据插入空
        QueuePush(pEmptyQ,QueueFront(pNonEmptyQ));
        //每区一个数据就把它Pop一下
        QueuePop(pNonEmptyQ);
    }
    int top=QueueFront(pNonEmptyQ);
    QueuePop(pNonEmptyQ);
    return top;
}

 

int myStackTop(MyStack* obj) {
    if(!QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }
    else
    {
        return QueueBack(&obj->q2);
    }
}
bool myStackEmpty(MyStack* obj) {
    return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}
void myStackFree(MyStack* obj) {
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    free(obj);
}

 如果不Destroy,可能会内存泄漏


这个题目完整代码如下:

typedef int QDataType;
// 链式结构:表示队列 
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QueueNode;
// 队列的结构 
typedef struct Queue
{
	QueueNode* phead;//头指针
	QueueNode* ptail;//尾指针
	int size;
}Queue;
// 初始化队列
void QueueInit(Queue* pq);

// 销毁队列 
void QueueDestroy(Queue* pq);

// 队尾入队列 
void QueuePush(Queue* pq, QDataType x);

// 队头出队列 
void QueuePop(Queue* pq);

// 获取队列头部元素 
QDataType QueueFront(Queue* pq);

// 获取队列队尾元素 
QDataType QueueBack(Queue* pq);

// 获取队列中有效元素个数 
int QueueSize(Queue* pq);

// 检测队列是否为空
bool QueueEmpty(Queue* pq);

// 初始化队列
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

// 销毁队列 
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QueueNode* cur = pq->phead;
	while (cur != NULL)
	{
		QueueNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

// 队尾入队列 
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;
	if (pq->ptail == NULL)
	{
		assert(pq->phead == NULL);
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}

// 检测队列是否为空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->phead == NULL && pq->ptail == NULL;
}

// 队头出队列 
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	//1.一个结点
	//2.多个节点
	if (pq->phead->next == NULL)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else
	{
		//相当于头删
		QueueNode* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
	pq->size--;
}

// 获取队列头部元素 
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->phead->data;
}

// 获取队列队尾元素 
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->ptail->data;
}

// 获取队列中有效元素个数 
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

typedef struct {
    Queue q1;
    Queue q2;
} MyStack;


MyStack* myStackCreate() {
    MyStack* obj=(MyStack*)malloc(sizeof(MyStack));
    if(obj==NULL)
    {
        perror("malloc fail");
        return NULL;
    }
    //这里->的优先级更高,取地址是对obj->q1和obj->q2取地址
    QueueInit(&obj->q1);
    QueueInit(&obj->q2);
    return obj;
}

void myStackPush(MyStack* obj, int x) {
    //q1不为空
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1,x);
    }
    else
    {
        QueuePush(&obj->q2,x);
    }
}

int myStackPop(MyStack* obj) {
    //由于不知道数据是在q1还是在q2
    //q1为空 q2不为空
    //这是一种假设 假设有可能错误
    Queue* pEmptyQ=&obj->q1;
    Queue* pNonEmptyQ=&obj->q2;
    //q1不为空
    if(!QueueEmpty(&obj->q1))
    {
        //q2为空 q1不为空
        pEmptyQ=&obj->q2;
        pNonEmptyQ=&obj->q1;
    }
    //导数据
    while(QueueSize(pNonEmptyQ)>1)
    {
        //非空里面的数据插入空
        QueuePush(pEmptyQ,QueueFront(pNonEmptyQ));
        //每区一个数据就把它Pop一下
        QueuePop(pNonEmptyQ);
    }
    int top=QueueFront(pNonEmptyQ);
    QueuePop(pNonEmptyQ);
    return top;
}

int myStackTop(MyStack* obj) {
    if(!QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }
    else
    {
        return QueueBack(&obj->q2);
    }
}

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

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

 


好啦,小雅兰今天的用队列实现栈的内容就到这里啦,还要继续加油刷题噢!!!

 

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

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

相关文章

本地 docker 发布 java 项目,连接本地 redis 配置

1、本地项目 install 相应的 jar 包到 target 目录下,jar 包的路径步骤 2 要填写 2、项目根目录下创建 Dockerfile 文件 # 使用官方的 Java 11 镜像作为基础镜像 FROM openjdk:11-jdk# 设置工作目录 WORKDIR /app# 复制应用程序 JAR 文件到镜像中的 /app 目录下 C…

用LangChain实现一个ChatBlog

文章目录 前言环境一、构建知识库二、将知识库向量化三、召回四、利用LLM做阅读理解五、效果总结 前言 通过本文, 你将学会如何使用langchain来构建一个自己的知识库问答 其实大多数类chatpdf产品的原理都差不多, 我将其简单粗暴地分为以下四步: 构建知识库将知识库向量化召回…

vue diff算法与虚拟dom知识整理(11) 书写patch父级新旧为同一节点 子节点与文字交换逻辑实现

上文我们简单描述了patch处理同一节点的大体逻辑 这次 我们就来看一下text替换的情况 我们更改案例入口文件 src下的 index.js 代码如下 import h from "./snabbdom/h"; import patch from "./snabbdom/patch";const container document.getElementById(…

Maven概念及搭建

1.为什么我们要学习 maven? maven 还未出世的时候,我们有很多痛苦的经历 。 痛点 1: jar 包难以寻找 痛点 2: jar 包依赖的问题 痛点 3: jar 不方便管理 痛点 4:项目编译 2.Maven 简介 Maven 是 Apache 软件基金…

Golang中的管道(channel) 、goroutine与channel实现并发、单向管道、select多路复用以及goroutine panic处理

目录 管道(channel) 无缓冲管道 有缓冲管道 需要注意 goroutine与channel实现并发 单向管道 定义单向管道 将双向管道转换为单向管道 单向管道作为函数参数 单向管道的代码示例 select多路复用 案例演示 goroutine panic处理 案例演示 管道…

APP服务端架构的演变

大家好,我是易安! 早期2013年的时候,随着智能设备的普及和移动互联网的发展,移动端逐渐成为用户的新入口,各个电商平台都开始聚焦移动端App,如今经历了10年的发展,很多电商APP早已经没入历史的洪…

日语文法PPT截图31-45

31 形式名词 とき ところ 作为形式名词的话,一般是要写假名不写汉字的 相对时态 如果是一般时/将来时とき,就是先做后面的动作,在做前面的动作。 出教室的时候,关灯。 如果是过去时とき那么,是先做前面的动作&#…

Linux安装elk

稍后补充。 目录 01【安装elk】 es单机 es集群 esHead插件 kibana logstash elastic search:https://www.elastic.co/cn/downloads/elasticsearchlogstash:https://www.elastic.co/cn/downloads/logstashkibana:https://www.elastic.co/cn/downloads/kibana linux下安装E…

vector的介绍

vector的介绍:(vector翻译是向量,但是表示的是顺序表) vector是表示可以改变大小的数组的序列容器。 就像数组一样,vector对其元素使用连续的存储位置,这意味着也可以使用指向其元素的常规指针上的偏移量来访问它们的元素&#xf…

前端代码规范配置

前端代码规范配置 涉及到了eslint、prettier、husky、lint-staged等工具包的使用。 代码规则校验 使用eslint定义代码风格 安装eslint并在.eslintrc.js文件中配置。 npm i eslint -D这个代码风格可以使用公司团队内的规范,如果没有可以在github中找到一些主流的…

主机访问不到虚拟机(centos7)web服务的解决办法

目录 一、背景 二、解决办法 2.1、配置虚拟机防火墙 2.2、修改虚拟机网络编辑器 一、背景 主机可以访问外网,虚拟机使用命令:curl http://网址,可以访问到web服务 ,主机使用http://网址,访问不到虚拟机&#xff08…

TikTok掀动出海淘金潮

嘉晟迪科:在各行各业都已经卷成红海的今天,最稀缺的是什么?当然是增长。那么,增长在哪里?流量在哪里,需求就在哪里,增长也就在那里。 因为短视频风靡全球的流行,内容平台特别是短视频…

Python-web开发学习笔记(2)--- HTML基础

先回顾一下上一篇文章&#xff1a;Python-web开发学习笔记&#xff08;1&#xff09;--- HTML基础_python web开发笔记_尚拙谨言的博客-CSDN博客 中讲了哪几个常用的HTML标签&#xff1a; <head>&#xff1a;头声明 <title>&#xff1a;网页标题 <h1>~<h6…

QT入门看这一篇就够了——超详细讲解(40000多字详细讲解,涵盖qt大量知识)

目录 一、Qt概述 1.1 什么是Qt 1.2 Qt的发展史 1.3 Qt的优势 1.4 Qt版本 1.5 成功案例 二、创建Qt项目 2.1 使用向导创建 2.2 一个最简单的Qt应用程序 2.2.1 main函数中 2.2.2 类头文件 2.3 .pro文件 2.4 命名规范 2.5 QtCreator常用快捷键 三、Qt按钮小程序 …

深度学习实战四:全连接神经网络(基于Pytorch,含数据和详细注释)

文章目录 概念softmax与交叉熵反向传播计算机视觉工具包torchvision全连接神经网络实现多分类概念 神经网络的第一层为输入层,最后一层为输出层,中间的所有层都叫做隐藏层 在计算神经网络层数时,一般不计算输入层,比如: 该神经网络的层数为2。输入层神经元有3个,隐藏层…

redis缓存数据库的使用

一&#xff0c;什么是redis &#xff1f;为什么要用它&#xff1f; 简单介绍&#xff1a; Redis是开源的key-value缓存框架&#xff0c;由c语言编写&#xff0c;也是一款高性能的框架提供多种语言的API 。 SET 每秒11万次 取get每秒81000次。 数据完全存储在内存空间中&…

【C++从0到王者】第八站:模板初阶

文章目录 一、泛型编程二、函数模板1.函数模板概念2.函数模板格式3.函数模板的原理4.函数模板的实例化1.隐式实例化2.显示实例化 5.模板参数的匹配原则 三、类模板1.类模板的格式2.类模板的实例化 一、泛型编程 当我们在写一个交换程序的时候 按照我们之前的想法&#xff0c;我…

谷歌算法快讯0519:近日排名变化频繁,排名或许回温?

从上周末到现在&#xff0c;已经有人注意到排名似乎又有了新的变化&#xff0c;根据WebMaster World上的帖子[1]和业内大家的讨论来看&#xff0c;大家共同的认识是5月16日开始就已经有变化&#xff0c;并且在5月19日的SEMRush Sensor来看已经到达峰值。 有一些在3月份谷歌更新…

yomichan使用笔记

导入词典词典下载 键盘快捷键 Alt Insert 打开搜索页面。 Alt DeleteToggle 打开/关闭扩展。 搜索结果中提供以下快捷方式&#xff1a; Esc取消当前搜索。 Alt PgUpPage 向上浏览结果。 Alt PgDnPage 向下浏览结果。 Alt End 转到最后一个结果。 Alt Home 转到第…

zookeeper的安装使用

zookeeper的安装使用 一、下载安装 https://zookeeper.apache.org/ 点击 download 以我自己的安装为例,linux,3.8.0 准备3台linux服务器&#xff1a;192.168.10.128、192.168.10.129、192.168.10.130 1.上传解压 把apache-zookeeper-3.8.0-bin.tar.gz 上传到 /usr/local/zo…