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

news2024/11/16 0:15:39

在这里插入图片描述

栈和队列小提升!

  • 前言
  • 一、用队列实现栈
    • 队列接口实现
    • (1)栈的接口定义
    • (2)栈的初始化
    • (3)入栈函数的定义
    • (4)出栈函数的定义
    • (5)查找栈顶元素
    • (6)判空函数的定义
    • (7)销毁函数的定义
  • 二、用栈实现队列
    • 栈的接口实现
    • (1)队列的接口定义
    • (2)队列的初始化
    • (3)入队函数的定义
    • (4)出队函数的定义
    • (5)查找队头函数的定义
    • (6)判空函数的定义
    • (7)销毁函数的定义
  • 三、设计循环队列
    • (1)循环队列的接口定义
    • (2)循环队列的初始化
    • (3)判空函数的定义
    • (4)判满函数的定义
    • (5)循环队列插入函数的定义
    • (6)循环队列删除函数的定义
    • (7)查找队头函数的定义
    • (8)查找队尾函数的定义
    • (9)销毁函数的定义
  • 总结


前言

欢迎来到专项提升小课堂!
今天的题目稍稍有难度哦!
但是只要用心,是难不倒同学们的!


一、用队列实现栈

题目链接:OJ链接
在这里插入图片描述
在这里插入图片描述

提示:
1 <= x <= 9;
最多调用100 次 push、pop、top 和 empty ;
每次调用 pop 和 top 都保证栈不为空;

核心思想:
用队列模拟出栈的先入后出这一特性!

解题思路:
此题可以用两个队列去实现一个栈,每次始终保持一个队列为空,
入栈操作相当于给非空队列进行入队操作
出栈操作相当于非空队列的队尾元素出队,此时需要把非空队列除最后一个元素之外的其余元素入队到空队列,然后出队最后一个队尾元素

图例解析:
在这里插入图片描述
在这里插入图片描述
代码示例:

队列接口实现

先将队列的实现接口导入

这里涉及到之前队列建立的内容啦!
如果不了解的可以去看看:栈和队列

//头文件的声明
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>


//链表接口定义
typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;


//队列接口定义
typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Que;


//队列初始化
void QueueInit(Que* pq);
//队列销毁
void QueueDestroy(Que* pq);
//插入
void QueuePush(Que* pq, QDataType x);
//删除
void QueuePop(Que* pq);
//查找队头元素
QDataType QueueFront(Que* pq);
//查找队尾元素
QDataType QueueBack(Que* pq);
//判断是否为空
bool QueueEmpty(Que* pq);
//计算长度
int QueueSize(Que* pq);

void QueueInit(Que* pq)
{
	assert(pq);


	pq->head = pq->tail = NULL;
	pq->size = 0;
}


void QueueDestroy(Que* 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(Que* pq, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}


	newnode->data = x;
	newnode->next = NULL;


	if (pq->tail == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}


	pq->size++;
}


void QueuePop(Que* pq)
{
	assert(pq);//判断队列指针指向是否为空
	assert(!QueueEmpty(pq));//判断队列里面的数据是否为空


	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}


	pq->size--;
}


//查找队头元素
QDataType QueueFront(Que* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));


	return pq->head->data;
}


//查找队尾元素
QDataType QueueBack(Que* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));


	return pq->tail->data;
}


//判断是否为空
bool QueueEmpty(Que* pq)
{
	assert(pq);


	return pq->head == NULL;
}


//长度计算
int QueueSize(Que* pq)
{
	assert(pq);


	return pq->size;
}

队列实现栈的功能函数的定义

(1)栈的接口定义

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

(2)栈的初始化

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

(3)入栈函数的定义

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

(4)出栈函数的定义

int myStackPop(MyStack* obj) {
    Que*Empty=&obj->q1;
    Que*nonEmpty=&obj->q2;
    if(!QueueEmpty(&obj->q1)){
        Empty=&obj->q2;
        nonEmpty=&obj->q1;
    }

    while(QueueSize(nonEmpty)>1){
        QueuePush(Empty,QueueFront(nonEmpty));
        QueuePop(nonEmpty);
    }

    int top = QueueFront(nonEmpty);
    QueuePop(nonEmpty);

    return top;
}

(5)查找栈顶元素

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

(6)判空函数的定义

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

(7)销毁函数的定义

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

    free(obj);
}

二、用栈实现队列

题目链接:OJ链接
在这里插入图片描述
在这里插入图片描述

提示:
1 <= x <= 9
最多调用 100 次 push、pop、peek 和 empty
假设所有操作都是有效的(例如,一个空的队列不会调用 pop 或者 peek 操作)

核心思想:
用栈模拟出队列的先入先出这一特性!

解题思路:
此题可以用两个栈实现,一个栈进行入队操作,另一个栈进行出队操作
出队操作: 当出队的栈不为空是,直接进行出栈操作,如果为空,需要把入队的栈元素全部导入到出队的栈,然后再进行出栈操作

图例解析
在这里插入图片描述
代码示例:

栈的接口实现

先将栈的实现接口导入

这里涉及到之前栈的建立的内容啦!
如果不了解的可以去看看:栈和队列

//栈的接口定义
typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;


//初始化
void STInit(ST* ps);
//销毁
void STDestroy(ST* ps);
//插入
void STPush(ST* ps, STDataType x);
//删除
void STPop(ST* ps);
//查找栈顶元素
STDataType STTop(ST* ps);
//长度计算
int STSize(ST* ps);
//判断是否为空
bool STEmpty(ST* ps);

//初始化
void STInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}


//销毁
void STDestroy(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}


//插入
void STPush(ST* ps, STDataType x)
{
	assert(ps);
	if (ps->top == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}


		ps->a = tmp;
		ps->capacity = newCapacity;
	}


	ps->a[ps->top] = x;
	ps->top++;
}


//删除栈顶元素
void STPop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);
	--ps->top;
}


//查找栈顶元素
STDataType STTop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);
	return ps->a[ps->top - 1];
}


//长度计算
int STSize(ST* ps)
{
	assert(ps);


	return ps->top;
}


//判断是否为空
bool STEmpty(ST* ps)
{
	assert(ps);


	return ps->top == 0;
}

栈实现队列的功能函数的定义

(1)队列的接口定义

typedef struct {
    ST pushst;
    ST popst;
} MyQueue;

(2)队列的初始化

MyQueue* myQueueCreate() {
    MyQueue*obj = (MyQueue*)malloc(sizeof(MyQueue));
    STInit(&obj->pushst);
    STInit(&obj->popst);
    return obj;
}

(3)入队函数的定义

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

(4)出队函数的定义

int myQueuePop(MyQueue* obj) {
    int front = myQueuePeek(obj);
    STPop(&obj->popst);
    return front;
}

(5)查找队头函数的定义

int myQueuePeek(MyQueue* obj) {
    if(STEmpty(&obj->popst))
    {
        while(!STEmpty(&obj->pushst)){
            STPush(&obj->popst,STTop(&obj->pushst));
            STPop(&obj->pushst);
        }
    }
    return STTop(&obj->popst);
}

(6)判空函数的定义

bool myQueueEmpty(MyQueue* obj) {
    return STEmpty(&obj->popst)&&STEmpty(&obj->pushst);
}

(7)销毁函数的定义

void myQueueFree(MyQueue* obj) {
    STDestroy(&obj->popst);
    STDestroy(&obj->pushst);

    free(obj);
}

三、设计循环队列

题目链接:OJ链接
在这里插入图片描述
在这里插入图片描述

提示:
所有的值都在 0 至 1000 的范围内;
操作数将在 1 至 1000 的范围内;
请不要使用内置的队列库。

核心思想:
首尾相连循环即为环形!

解题思路:
通过一个定长数组实现循环队列
入队:首先要判断队列是否已满,再进行入队的操作,入队操作需要考虑索引循环的问题,当索引越界,需要让它变成最小值
出队:首先要判断队列是否为空,再进行出队操作,出队也需要考虑索引循环的问题
判空: 队头 == 队尾
判满: 队尾 + 1 == 队头

图例解析:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码示例:

(1)循环队列的接口定义

typedef struct {
    int *a;
    int front;
    int rear;
    int k;
} MyCircularQueue;

(2)循环队列的初始化

MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));

    obj->a=(int*)malloc(sizeof(int)*(k+1));
    obj->front=obj->rear=0;
    obj->k=k;
    return obj;
}

(3)判空函数的定义

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->front==obj->rear;
}

(4)判满函数的定义

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->rear+1)%(obj->k+1)==obj->front;
}

(5)循环队列插入函数的定义

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
        return false;
    
    obj->a[obj->rear]=value;
    obj->rear++;
    obj->rear%=(obj->k+1);
    return true;
}

(6)循环队列删除函数的定义

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return false;
    ++obj->front;
    obj->front%=(obj->k+1);
    return true;
}

(7)查找队头函数的定义

int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return -1;
    else
        return obj->a[obj->front];
}

(8)查找队尾函数的定义

int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return -1;
    else
        return obj->a[(obj->rear+obj->k)%(obj->k+1)];
}

(9)销毁函数的定义

void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->a);
    free(obj);
}

总结

今天的题目难度真的不小哦!
但也要相信自己!
自信就是最好解决问题的方法!

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

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

相关文章

数据清洗——气温历史数据

import pandas as pd import numpy as np import matplotlib.pyplot as plt from pylab import mpl mpl.rcParams["font.sans-serif"] ["HarmonyOS Sans SC"] %matplotlib inline读取数据 data pd.read_excel("气温历史数据.xlsx") data.head…

【golang】for语句和switch语句

使用携带range子句的for语句时需要注意哪些细节&#xff1f; numbers1 : []int{1, 2, 3, 4, 5, 6} for i : range numbers1 {if i 3 {numbers1[i] | i} } fmt.Println(numbers1)这段代码执行后会打印出什么内容&#xff1f; 答案&#xff1a;[1 2 3 7 5 6] 当for语句被执行…

【面试题系列】(一)

Redis有哪些数据结构&#xff1f;其底层是怎么实现的&#xff1f; Redis 系列&#xff08;一&#xff09;&#xff1a;深入了解 Redis 数据类型和底层数据结构 字符串&#xff08;String&#xff09;&#xff1a; 用于存储文本或二进制数据。可以执行字符串的基本操作&#xf…

只需五分钟,了解kafka的环境搭建

〇、前言 在Kafka系列的上一篇文章中&#xff0c;我们介绍了Kafka的体系结构&#xff0c;那么本篇文章呢&#xff0c;我们就着手来把Kafka的运行环境搭建起来。 此处 &#xff0c;我们采用线上环境普遍使用的ZooKeeper作为管理存储和管理kafka集群元数据&#xff0c;或者辅助…

更高效稳定 | 基于ACM32 MCU的编程直流电源应用方案

随着电子设备的多样化发展&#xff0c;面对不同的应用场景&#xff0c;需要采用特定的供电电源。因此&#xff0c;在电子产品的开发测试过程中&#xff0c;必不可少使用编程直流电源来提供测试电压&#xff0c;协助完成初步的开发测试过程。 编程直流电源概述 编程直流电源结构…

收单外包服务机构(第三方支付公司服务商)是什么?

收单外包服务机构&#xff08;第三方支付公司服务商&#xff09;是什么&#xff1f; 伴随着电子商务的迅速发展&#xff0c;越来越多的企业开始认识到收单外包服务机构的重要性。 收单外包是一个重要的服务机构&#xff0c;可以帮助企业解决许多与支付相关的问题。 收单外包服务…

行式存储与列式存储

1.概述 数据处理大致可分为两大类&#xff0c;联机事务处理OLTP(on-line transaction processing) 和联机分析处理OLAP(on-line analytical processing)。 OLTP是传统关系型数据库的主要应用&#xff0c;用来执行一些基本的、日常的事务处理&#xff0c;比如数据库记录的增、删…

漏洞复现 || Franklin Fueling Systems tsaupload.cgi 任意文件读取

漏洞描述 Franklin Electric Franklin Fueling Systems是美国Franklin Electric公司的一个加油系统&#xff0c;Franklin Fueling Systems tsaupload.cgi 存在任意文件读取漏洞&#xff0c;攻击者通过漏洞可以获取服务器敏感文件。 免责声明 技术文章仅供参考&#xff0c;任…

SpringMVC中Controller层获取前端请求参数的几种方式

SpringMVC中Controller层获取前端请求参数的几种方式 1、SpringMVC自动绑定2、使用RequestParam 注解进行接收3、RequestBody注解&#xff08;1&#xff09; 使用实体来接收JSON&#xff08;2&#xff09;使用 Map 集合接收JSON&#xff08;3&#xff09; 使用 List集合接收JSO…

C语言暑假刷题冲刺篇——day4

目录 一、选择题 二、编程题 &#x1f388;个人主页&#xff1a;库库的里昂 &#x1f390;CSDN新晋作者 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏✨收录专栏&#xff1a;C语言每日一练 ✨其他专栏&#xff1a;代码小游戏C语言初阶&#x1f91d;希望作者的文章能对你…

iOS逆向初探:揭开iOS App的神秘面纱

逆向是一种分析和还原应用程序的过程&#xff0c;它能够揭示应用程序内部的工作原理和代码结构。接下来我们将全面介绍iOS上的逆向&#xff0c;包括其概念、常用工具和具体实例。 1. 什么是iOS逆向&#xff1f; iOS平台逆向是将应用程序的二进制代码&#xff08;通常是经过编…

无涯教程-Python - Numbers(数字)

数字数据类型存储数值&#xff0c;它们是不可变的数据类型&#xff0c;这意味着更改数字数据类型的值将导致新分配的对象。 数字对象是在您为其分配值时创建的。例如- var11 var210 您也可以使用 del 语句删除对数字对象的引用。 del语句的语法是- del var1[,var2[,var3[..…

基于XML实现SpringIoC配置

目录 SpringIoc创建与使用的大致步骤 一.基于xml配置SpringIoc 二.基于xml配置DI 三.创建IoC容器并获取组件 SpringIoc创建与使用的大致步骤 SpringIoC的创建与使用过程分为3步 1.编写配置信息&#xff08;编写XML&#xff0c;注解、Java类&#xff09; 2.创建IoC容器&…

易基因:WGBS等揭示丹参甲基化表征及DNA甲基化在丹参酮生物合成中的调控机制|科研速递

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 丹参&#xff08;Salvia miltiorrhiza&#xff0c;S. miltiorrhiza&#xff09;是一种具有重要经济价值和药用价值的模式药用植物&#xff0c;丹参的根会合成一组称为丹参酮&#xff08;…

SpringBoot案例-配置文件-参数配置化

前言 目前我们已经完成了部门管理和员工管理功能接口的实现&#xff0c;阿里云OSS工具类中&#xff0c;我们会设置4个参数&#xff0c;分别是云服务域名、云服务ID和密码、文件存储的Bucket、就会存在以下问题&#xff1a;参数配置分散以及参数发生变化&#xff0c;就需要对应…

姜启源数学模型第五版第五章火箭发射升空

姜启源数学模型第五版第五章例题内容复现 数学建模背景1.学习内容火箭发射升空理论知识 2.例题3.问题分析不考虑空气阻力的模型考虑空气阻力的模型 4.代码内容复现不考虑空气阻力考虑空气阻力模型 数学建模背景 首先先简单的介绍数学建模是一个怎么样的内容 数学建模是一种将数…

各种文件类型

1.配置文件 json app.json 是当前⼩程序的全局配置&#xff0c;包括了⼩程序的所有⻚⾯路径、界⾯表现、⽹络超时时间、底 部 tab 等。 普通快速启动项⽬ ⾥边的 app.json 字段的含义 1. pages 字段⸺⽤于描述当前⼩程序所有⻚⾯路径&#xff0c;这是为了让微信客⼾端知道…

NIO原理浅析(一)

IO简介 摘抄了下维基百科对IO的定义&#xff0c;Input/Output&#xff0c;输入和输出&#xff0c;通常指数据在存储器或者其他周边设备之间的输出和输入&#xff0c;输入是系统接收到信号或者数据&#xff0c;输出则是从系统发送的信号或数据。 Java IO 读写原理 Java中文件…

shell邮件发送脚本

先上整体代码 text.sh #!/bin/bash# 设置收件人邮箱 to"123456qq.com"# 设置发件人邮箱 from"21331qq.com"# 设置邮件主题 subject"Test Email"# 设置邮件内容 body"This is a test email."# 发送邮件 echo "${body}" | m…

运动耳机啥样的好用、最适合运动用的耳机推荐

在进行运动时&#xff0c;倾听音乐实际上是一种放松大脑、放松身体的小技巧。毕竟运动是一个耗费体力最多的活动&#xff0c;整个过程也往往令人感到乏味。如果有音乐作伴&#xff0c;你的运动就会变得更加轻松愉快。那么&#xff0c;哪种耳机适合运动呢&#xff1f;我正好对此…