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

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);
}

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

linux学习:内存(栈,堆,数据段,代码段)

目录 内存 栈内存 堆内存 数据段 代码段 注意 堆 例子 内存 Linux 操作系统为了更好更高效地使用内存,将 实际物理内存进行了映射,对应用程序屏蔽了物理内存的具体细节,有利于简化程序的编写 和系统统一的管理。 假设你正在使用的…

苍穹外卖jwt令牌p10

点击小虫(进入断点调试),打上断点,然后前端点击登录(此时前端的数据会作为参数传入): 光标放在字段上还会显示接收到的数据: 若想程序在所希望的地方停止,可以添加断点&a…

NetSuite中Inactive Item后相关Transaction是否能继续?

今天的标题以一个问句出发~灵感来源于我们在一个项目上要准备数据切换的事宜,我们需要明确,将一个物料Inactive之后,涉及到该Item的Transaction是否还能在业务或者财务处理的环节继续操作~基本的测试分三种场景&#x…

【Linux】基础IO----系统文件IO 文件描述符fd 重定向

> 作者:დ旧言~ > 座右铭:松树千年终是朽,槿花一日自为荣。 > 目标:了解在Linux下的系统文件IO,知道什么是文件描述符,什么是重定向 > 毒鸡汤:白日莫闲过,青春不再来。 …

实验2-1 进程相关的系统调用

一、实验目的 学习Linux中与进程控制相关的系统调用,加深对进程、进程树等概念的理解。 二、实验内容 1. 学习使用以下几类系统调用,进行编程练习 获取进程的信息,getpid(), getppid() 父子进程控制,fork(),wai…

前端三剑客 —— JavaScript (第九节)

目录 内容回顾: 1.事件解除 2. Ajax jQuery选择器 回顾CSS选择器 CSS选择 1.基本选择器 2.包含选择器 3.伪类选择器 4.伪元素选择器 5.属性选择器 jQuery 库 jQuery 动画 系统动画 自定义动画 常见API操作 内容回顾: 1.事件解除 如果是使…

一文读懂RISC-V与ARM

RISC-V和ARM是近年来备受关注的两种处理器架构。RISC-V是一种基于精简指令集计算(RISC)原理的开源指令集架构(ISA),而ARM是一种专有ISA,由于其长期存在于嵌入式系统和移动设备中,已成为嵌入式系统和移动设备的主导选择。市场以及多年积累的信…

安装图数据库Nebula Graph

前言 今年开始,很多机关单位、央国企都要求所有新建的信息系统必须走国产化技术路线,而且还要求满足“信创”要求。“信创”通俗来讲就是要自研,那种拿个开源套壳的都不满足信创要求。之前研究了一段时间的neo4j,显然neo4j不满足…

雪亮工程视频联网综合管理/视频智能分析系统建设方案(一)

一、行业背景 雪亮工程主要是针对农村地区治安防控的监控项目,在乡村的主干道、路口、人群聚集地部署高清摄像头,通过三级综治中心和指挥平台,将视频图像信息系统纵向下延至县、乡、村,同时利用系统拓展在安防、社会治理、智慧交…

MWeb Pro For Mac v4.5.9 强大的 Markdown 软件中文版

MWeb 是专业的 Markdown 写作、记笔记、静态博客生成软件,目前已支持 Mac,iPad 和 iPhone。MWeb 有以下特色: 软件下载:MWeb Pro For Mac v4.5.9 软件本身: 使用原生的 macOS 技术打造,追求与系统的完美结合…

Linux从入门到精通 --- 3.用户、权限

文章目录 第三章:3.1 root用户3.1.1 su3.1.2 exit3.1.3 sudo 3.2 用户和用户组3.2.1 用户组管理创建用户组删除用户组 3.2.2 用户管理创建用户删除用户查看用户所属组修改用户所属组 3.2.3 getent一:二: 3.3 查看权限控制信息3.3.1 认知权限信…

IDEA 控制台中文乱码 4 种解决方案

前言 IntelliJ IDEA 如果不进行相关设置,可能会导致控制台中文乱码、配置文件中文乱码等问题,非常影响编码过程中进行问题追踪。本文总结了 IDEA 中常见的中文乱码解决方法,希望能够帮助到大家。 IDEA 中文乱码 解决方案 一、设置字体为支…

软件安全评估之设计评审入门(上)

壹 基础概念 在软件开发生命周期(Software Development Life Cycle,简称SDLC)中,设计评审(Design Review)是一个关键的阶段,旨在确保软件设计满足项目需求和目标,并且能够高效、可靠…

GDAL源码剖析(九)之GDAL体系架构

GDAL源码剖析(九)之GDAL体系架构_gdal 源码-CSDN博客 在GDAL库中包含栅格数据的读写,矢量数据的读写,以及栅格和矢量数据的相关算法。下面主要对GDAL中栅格数据和矢量数据的体系架构做一个简单的说明。本人英文很烂,有…

集装箱5G智能制造工厂数字孪生可视化平台,推进企业数字化转型

集装箱5G智能制造工厂数字孪生可视化平台,推进企业数字化转型。在当下数字化转型的热潮中,集装箱5G智能制造工厂数字孪生可视化平台成为了推动企业转型升级的重要工具。这一平台将先进的5G技术与智能制造相结合,通过数字孪生技术实现生产过程…

数字化赋能农业创新发展新篇章:数字乡村建设推动农业现代化、提升农业综合效益与竞争力

目录 一、数字乡村建设的内涵与意义 二、数字化赋能农业创新发展的路径 1、推动智慧农业发展 2、加强农村电子商务建设 3、提升农业信息化水平 三、数字乡村建设推动农业现代化与提升综合效益与竞争力 1、推动农业现代化进程 2、提升农业综合效益 3、增强农业竞争力 …

HTML5+CSS3+JS小实例:图片切换特效之模糊变清晰

实例:图片切换特效之模糊变清晰 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, i…

Windows搭建Jellyfin影音服务结合内网穿透实现公网访问本地视频文件

文章目录 1. 前言2. Jellyfin服务网站搭建2.1. Jellyfin下载和安装2.2. Jellyfin网页测试 3.本地网页发布3.1 cpolar的安装和注册3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5. 结语 1. 前言 随着移动智能设备的普及&#xff0c;各种各样的使用需求也被开发出来&…

大势智慧在出模型时输入七参数可以导出地方坐标系吗?

大势智慧自主研发的网格大师或者DasViewer有坐标转换功能&#xff0c;可以使用七参数计算功能转换到地方坐标&#xff0c;直接输以前的七参是不行的&#xff0c;需要准备源坐标和目标坐标。 DasViewer是由大势智慧自主研发的免费的实景三维模型浏览器,采用多细节层次模型逐步自…

【Unity】组件组合使用心得(单行可自动拓展Scroll View)

在这之前&#xff0c;一直是在使用Scroll View进行滑动内容设置&#xff0c;但设置的都是不明不白的&#xff0c;而且有的时候设置好了之后也不知道是为什么&#xff0c;总感觉哪里不对劲&#xff0c;而且好也不知道为什么好&#xff0c;可能是长时间在做管理上的内容&#xff…