数据结构OJ题——栈和队列

news2025/2/25 15:37:19

1. 用栈实现队列(OJ链接)

题目描述:请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty)

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

假设入队的顺序是1,2,3,4,5,那么出队的顺序也需要是1,2,3,4,5
栈的性质是先进后出,但是我们有两个栈,如果把数据pop到另一个栈中,再出数据,那么会怎么样呢?

看下图。
在这里插入图片描述
此时我们从stack2中出数据会发现,出队的顺序变成了1,2,3,4,5
此时需要进数据的话,就需要进入到stack1,当stack2为空时,若需要pop数据,则将stack1的数据倒到stack2中再进行pop。

那么push和pop操作就可以理解为:有两个栈,stack1和stack2,push数据时永远push到stack1中,pop数据从stack2中pop,如果stack2为空,那么将stack1中的数据全部倒到stack2中,再进行pop。

peek操作为获取队头元素,由于经过一轮的倒入,再stack2中的栈顶数据就是队头了,直接返回该数据即可,如果stack2为空,则需要先从stack1中入数据到stack2中。

判空操作:两个栈都为空,那么队列就为空。

用栈实现队列,我们需要一个栈的数据结构,之前已经写过了,这里直接拷贝过来用即可。
完整代码如下

typedef int STDataType;

typedef struct StackNode
{
	int capacity;      //最大容量
	int top;           //栈顶数据的下一个位置
    STDataType* arr;   //数组
}STNode;

//初始化顺序栈
void StackInit(STNode* ps)
{
	ps->arr = NULL;
	ps->capacity = 0;
	ps->top = 0;
}
//销毁栈
void StackDestroy(STNode* ps)
{
	free(ps->arr);
	ps->arr = NULL;
	ps->capacity = ps->top = 0;
}
//入栈
void StackPush(STNode* ps, STDataType x)
{
	//没有空间或者空间满了,先扩容
	if (ps->capacity == ps->top)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->arr,sizeof(STNode) * newcapacity);
		if (tmp == NULL)
		{
			perror("malloc()");
			return;
		}
		ps->arr = tmp;
		ps->capacity = newcapacity;
	}
	//插入数据
	ps->arr[ps->top++] = x;

}
//出栈
void StackPop(STNode* ps)
{
	ps->top--;
}
//判断栈空
bool StackEmpty(STNode* ps)
{
	return ps->top == 0;
}
//获得栈顶元素
int FindTop(STNode* ps)
{
	return ps->arr[ps->top - 1];
}

typedef struct 
{
    STNode stack1;//push数据的栈
    STNode stack2;//pop数据的栈
} MyQueue;


MyQueue* myQueueCreate() 
{
    MyQueue* obj=(MyQueue*)malloc(sizeof(MyQueue));
    StackInit(&obj->stack1);
    StackInit(&obj->stack2);
    return obj;
}

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

int myQueuePop(MyQueue* obj) 
{
    //栈一不是空,栈二是空
    if(!StackEmpty(&obj->stack1)&&StackEmpty(&obj->stack2))
    {
        //将数据移到栈二
        while(!StackEmpty(&obj->stack1))
        {
            StackPush(&obj->stack2,FindTop(&obj->stack1));
            StackPop(&obj->stack1);
        }
        int ret=FindTop(&obj->stack2);
        StackPop(&obj->stack2);
        return ret;
    }
    //栈二有数据,直接pop
    else
    {
        int ret=FindTop(&obj->stack2);
        StackPop(&obj->stack2);
        return ret;
    }
}

int myQueuePeek(MyQueue* obj) 
{
    //栈二没有数据
    if(StackEmpty(&obj->stack2))
    {
        //将栈一的数据移到栈二
        while(!StackEmpty(&obj->stack1))
        {
            StackPush(&obj->stack2,FindTop(&obj->stack1));
            StackPop(&obj->stack1);
        }
    }
    //返回栈顶数据
    return FindTop(&obj->stack2);
}

bool myQueueEmpty(MyQueue* obj) 
{
    return StackEmpty(&obj->stack1)&&StackEmpty(&obj->stack2);
}

void myQueueFree(MyQueue* obj) 
{
    StackDestroy(&obj->stack1);
    StackDestroy(&obj->stack2);
    free(obj);
}

代码虽然看着很长,但是其中三分之二都是之前写过的,这里只是拿来运用而已。下一题也是如此。

2. 用队列实现栈(OJ链接)

题目描述:请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

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

假设入队数据1,2,3,4,5由于需要实现栈,那么出数据的顺序需要是5,4,3,2,1,效仿上一题,将数据倒入到另一个队列后,发现再出数据还是1,2,3,4,5,因此这个方法不适用了。

需要出的数据是5,所以可以考虑把1,2,3,4倒入到另一个队列,再把5出出去。把1,2,3倒回来,把4再出出去,循环就可以实现出数据的顺序为5,4,3,2,1了

过程如图所示
在这里插入图片描述
最终的数据序列就是5,4,3,2,1

push数据时,需要往非空的队列内push,需要后进先出。

pop数据时需要将非空队列的前n-1个数据入到空队列里(假设非空队列有n个数据),再pop最后一个数据。

top:栈顶数据就是非空队列的队尾

empty:两个队列都为空,则栈为空

完整代码如下

typedef int QDataType;

typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType val;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;

void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);

void QueuePush(Queue* pq,QDataType x);
void QueuePop(Queue* pq);
int QueueSize(Queue* pq);

QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);

bool QueueEmpty(Queue* pq);

//初始化队列
void QueueInit(Queue* pq)
{
	assert(pq);

	pq->head = pq->tail = NULL;
	pq->size = 0;
}
//销毁队列
void QueueDestroy(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;
}
//队尾入队
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);

	//创建新节点
	QNode* newNode = (QNode*)malloc(sizeof(QNode));
	if (newNode == NULL)
	{
		return;
	}
	newNode->val = x;
	newNode->next = NULL;
	//队列为空
	if (pq->head == NULL)
	{
		pq->head = pq->tail = newNode;
	}
	//队列不为空
	else
	{
		pq->tail->next = newNode;
		pq->tail = newNode;
	}

	pq->size++;
}
//队头出队
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));   //队列不能为空
	//只有一个结点
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	
	else
	{
		QNode* cur = pq->head->next;  //保留第二个结点
		free(pq->head);
		pq->head = cur;
	}

	pq->size--;
}
//队列大小
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}
//队头元素
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->head->val;
}
//队尾元素
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->tail->val;
}
//判空
bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->size == 0;
}

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


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

void myStackPush(MyStack* obj, int x) 
{
    //将数据插入非空的队列
    if(QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q2,x);
    }
    else
    {
        QueuePush(&obj->q1,x);
    }
}

int myStackPop(MyStack* obj) 
{
    //找到空的队列
    Queue* Empty=&obj->q1;
    Queue* NotEmpty=&obj->q2;
    if(!QueueEmpty(&obj->q1))
    {
        Empty=&obj->q2;
        NotEmpty=&obj->q1;
    }
    //将非空队列前n-1个数据导入到空队列
    while(QueueSize(NotEmpty)>1)
    {
        QueuePush(Empty,QueueFront(NotEmpty));
        QueuePop(NotEmpty);
    }
    //pop掉最后一个
    int popData=QueueFront(NotEmpty);
    QueuePop(NotEmpty);
    return popData;

}

int myStackTop(MyStack* obj) 
{
    //栈顶数据就是非空队列的最后一个数据
    if(QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q2);
    }
    else
    {
        return QueueBack(&obj->q1);
    }
}

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

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

同样,三分之二的代码是之前写过的,这里只需要拷贝过来使用即可。
运行结果如下图
在这里插入图片描述

3. 设计循环队列(OJ链接)

题目描述:循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满。

假设k等于5,即队列的长度等于5,最多存五个数据。
这里采用数组来实现循环队列。

定义的结构体类型如下

typedef struct {
    int* a;      //数组
    int front;   //指向队头
    int tail;    //指向队尾下一个位置
    int k;       //队列元素个数
} MyCircularQueue;

在这里插入图片描述
开辟k个空间会有上述的歧义,所以选择多开一个空间,即开辟k+1个空间,那么队列为空时是front=tail
在这里插入图片描述
将上面两种情况综合,队列为满时判断条件是 ( tail + 1 ) % ( k + 1 ) = front;

出队和入队也需要注意下标的回绕,也就是求余操作,也可以使用判断语句。

完整代码如下

typedef struct {
    int* a;      //数组
    int front;   //指向队头
    int tail;    //指向队尾下一个位置
    int k;       //队列元素个数
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->a=(int*)malloc(sizeof(int)*(k+1));
    obj->front=obj->tail=0;
    obj->k=k;
    return obj;
}

//判空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->front==obj->tail;
}
//判满
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->tail+1)%(obj->k+1)==obj->front;
}
//入队
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    //队列满了
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    //入队
    obj->a[obj->tail++]=value;
    //下标回绕
    if(obj->tail==obj->k+1)
    {
        obj->tail=0;
    }
    return true;
}
//出队
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    //队列为空
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    //出队
    obj->front++;
    //下标回绕
    if(obj->front==obj->k+1)
    {
        obj->front=0;
    }
    return true;
}
//队头元素
int myCircularQueueFront(MyCircularQueue* obj) {
    //空队列返回-1
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->a[obj->front];
}
//队尾元素
int myCircularQueueRear(MyCircularQueue* obj) {
    //空队列返回-1
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    //返回最后一个值
    if(obj->tail==0)
    {
        return obj->a[obj->k];
    }
    return obj->a[obj->tail-1];
}
//释放空间
void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->a);
    free(obj);
}

关于栈和队列的题目,就写到这里了。

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

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

相关文章

Mysql安装和初始化密码

一、下载地址: MySQL :: Download MySQL Community Server (Archived Versions) 1、解压到本地目录下,然后配置环境变量(也可以不配置,不影响使用,不过为了区分多版本的MySQL最好配置一下系统变量) 复制…

分享:temu跨境电商项目是真的能赚钱吗?有哪些技巧?

近年来,跨境电商成为了一个备受瞩目的领域,temu跨境电商项目也吸引了众多创业者和投资者的目光。那么,temu跨境电商项目真的能够赚钱吗?又有哪些技巧可以帮助我们在这个领域取得成功呢? 首先,可以肯定的是,temu跨境电…

谷歌查问题

1,打开 it工具箱-里面啥都有 2,找到谷歌 3,访问gpt

使用LNMP部署动态网站环境

目录 实验环境 一、配置LNMP架构环境 二、验证部署的LNMP 动态网站环境是否可用 三、配置过程中遇到的问题及解决思路 实验环境 centos7 192.168.81.131/24 一、配置LNMP架构环境 概念及配置手册参考第20章 使用LNMP架构部署动态网站环境。 | 《Linux就该这么学》 安装g…

开源项目ChatGPT-Next-Web的容器化部署(四)-- k8s容器部署使用configmap配置

一、接着上文 本文的内容是在k8s容器中,如何使用configmap对.env文件进行挂载,实现环境的差异化配置。 二、源码结构 项目ChatGPT-Next-Web使用了.env文件来配置不同环境下的值: 所以,我们同理新增两个配置文件,见下…

PixArt-β:Fast and controllable image generation with latent consistency models

PixArt α to Σ: All about Efficient Diffusion Models - 知乎前言自年初Sora和Stable Diffusion 3推出以来,笔者就开始关注基于Diffusion Transformer的工作。在我的往期文章《 Diffusion Transformer Family:关于Sora和Stable Diffusion 3你需要知道…

跟TED演讲学英文:A new way to build AI, openly by Percy Liang

A new way to build AI, openly Link: https://www.ted.com/talks/percy_liang_a_new_way_to_build_ai_openly? Speaker: Percy Liang Date: October 2023 文章目录 A new way to build AI, openlyIntroductionVocabularyTranscriptSummary后记 Introduction Today’s AI …

HiSilicon352 android9.0 系统显示方向旋转与截屏问题分析

一,系统显示方向 1. 概述 Android的旋转显示,主要运用于广告机。Android的旋转,包括图形UI的旋转、鼠标和遥控器的旋转及媒体旋转。 下图为竖屏UI的绘制坐标系和显示坐标系。 2. 功能说明 方案依据Android原生的旋转原理设计&#xff0c…

“安全边际大师”卡拉曼2023年珍贵访谈:如果视市场为狂躁的交易对手,那你就能利用反复无常来获利

“对于那些被广泛跟踪的股票,如果你不比其他人更聪明,且你的观点与别人无异,你是赚不到钱的。” “足够大的折价也许可以抵消你对它缺乏最深刻的认识。” “拓宽投资视野不仅诱人,也可能价值连城。” “如果向市场寻求答案&…

JAVA面试八股文之数据库

MySQL面试题 MySQL 存储引擎架构了解吗?CHAR 和 VARCHAR 的区别是什么?索引是越多越好嘛?MySQL数据库中空值(null)和空字符串()的区别?SQL 中 on 条件与 where 条件的区别&#xff1…

Java创建对象内存分析-JVM

Java 创建对象的内存分析-JVM 复习的时候看到这篇,看完自己背着画了一下。 https://blog.csdn.net/qq_60264381/article/details/119276824

进军俄罗斯市场,一站式Yandex广告开户与代运营服务

俄罗斯作为欧洲最大的经济体之一,拥有庞大的消费者群体和独特的市场环境,成为了众多国际商家关注的焦点。要有效地触达这片潜力无限的市场,精准且高效的网络营销策略至关重要。利用Yandex——俄罗斯最大的搜索引擎与数字广告平台,…

【LAMMPS学习】八、基础知识(1.3)从一个输入脚本运行多个模拟

8. 基础知识 此部分描述了如何使用 LAMMPS 为用户和开发人员执行各种任务。术语表页面还列出了 MD 术语,以及相应 LAMMPS 手册页的链接。 LAMMPS 源代码分发的 examples 目录中包含的示例输入脚本以及示例脚本页面上突出显示的示例输入脚本还展示了如何设置和运行各…

ELK——日志处理界的瑞士军刀

目录 引言 一、ELK简介 (一)基本概述 1.Elasticsearch服务 2.Logstash服务 2.2 logstash关键组件 2.2 logstash数据流向 3.Kibana服务 (二)ELK工作流程 (三)ELK的应用价值 二、部署搭建ELK &…

如何使用Android手机通过JuiceSSH远程访问本地Linux服务器

文章目录 1. Linux安装cpolar2. 创建公网SSH连接地址3. JuiceSSH公网远程连接4. 固定连接SSH公网地址5. SSH固定地址连接测试 处于内网的虚拟机如何被外网访问呢?如何手机就能访问虚拟机呢? cpolarJuiceSSH 实现手机端远程连接Linux虚拟机(内网穿透,手机端连接Linux虚拟机) …

Cuda编程-NPP库

Cuda编程先前有过研究,现在记录下Cuda相关的库使用 目录 0.参考文档1.NPP简介1.1 头文件1.2 库文件1.3 编译时链接关系1.4 NPP函数的命名方式1.5 General Conventions 一般约定1.6 Image Processing Conventions 图像处理约定 2.举例:NPP实现YUV转BGR2.1…

从 auto 到 Lambda:全面解析 C++11 核心新特性

在介绍 C11 之前,我们先回顾一下 C98和C03。C98 作为 C 的第一个国际标准,奠定了这门语言的基础结构和核心特性,比如类、继承、模板、异常处理等。这些特性使得 C 成为一门强大的、面向对象的编程语言,广泛应用于系统/应用软件、游…

vue3中ElMessage如何动态更改提示消息

1.需求 要求ElMessage的提示消息做成倒计时的效果 2.效果 3.实现代码 function shower(){const message ElMessage({type: warning, // 提示类型dangerouslyUseHTMLString: true, // 使用 HTML 片段作为正文内容message: <div id"kanno"><span>不敢吃…

js 数组 按列循环二维数组

期待效果&#xff1a; 核心代码&#xff1a; //js function handle(array) {var result [];for (let i 0; i < array[0].length; i) {var item []; for (let j 0; j < array.length; j) {item.push(array[j][i])} result.push(item);} return result; } 运行代码&a…

数据库体系概述:详述其基本概念、多样分类、关键作用及核心特性

数据库是一个用于存储、管理和检索数据的系统&#xff0c;它按照特定的数据结构和模式组织数据&#xff0c;确保数据的一致性、安全性和高效访问。 数据库&#xff08;Database, DB&#xff09;是一个长期存储在计算机内&#xff0c;用来组织、存储和管理大量数据的集合。数据…