数据结构:队列 || oj(l两个队列实现栈)

news2024/11/17 9:52:07

@[TOC](数据结构:队列 || oj(l两个队列实现栈))

一、队列的概念

1.什么是队列?
//先说一下,队列跟栈一样都是很重要的数据结构,重要的不是说这个数据结构怎么实现,重要的是结构的优势!
//栈:是先入先出,选的最好的是底层用数组,来实现,可以栈顶入,栈顶出,复杂度都是O(1),在就是CPU高速缓存,缓存线取数据(好像一般是64个字节),取数据效率高!,比链表好一点,用链表的话,单链表头做栈顶,用做压数据,和取数据都可以!
//队列:这种数据结构的要求是:先入先出,不能用数组来实现,原因是:如果把数组后面当尾巴,队尾入数据这个可以,队头出数据要挪动数据,时间复杂度是O(n),因此用链表来实现队列!

2.队列的概念
//队列:只允许在一段插入数据操作,在另一端删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)
// 入队列:进行插入操作的一端称为队尾
// 出队列:进行删除操作的一端称为队头
//队尾入,队头出

1

//队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
1
//用链表实现队列,链表头用作队列头取数据,链表尾用作队列尾巴,插(放)数据!
//定义节点:
typedef int QDataType ;
typedef struct QListNode{
  int val;
  struct QListNode* next;
}QLNode;
//这样定义一个链表有个问题,头删当然可以,尾插呢?时间复杂度是O(n),那么可以定义一个头指针(head),一个尾指针(tail)来解决这个问题,还要考虑统计在队列中数据的个数,因此在定义一个int Size;那么把这些数据放在一个结构体中,就很好的解决了这个问题!因此:
typedef struct Queue{
  QLNode* head;
  QLNode* tail;
  int Size;
}Queue;
//这样这个栈就定义好了,这样定义的好处是:只要传Queue的地址,就可以改变head和tail和Size的值了,如果单独写,那么改变head的内容,则要QLNode** 来接受,可以规避这一点,还有就是头,尾都有标记,随便可以搞!

//下面来实现队列
//定义队列

//存储队列的数据

typedef int QDataType;

typedef struct QListNode {
	QDataType val;
	struct QListNode* next;
}QLNode;


//用结构体来存储队头,队尾,数据个数

typedef struct Queue {
	QLNode* head;
	QLNode* tail;
	int size;    //存储数据的个数
}Queue;

//实现的接口如下,虽然有些接口没用到,但是以后肯定用!
//初始化
void QueueInit(Queue* pq);
//销毁
void QueueDestory(Queue* pq);
//队尾入数据
void QueuePush(Queue* pq,QDataType x);
//队头出数据
void QueuePop(Queue* pq);
//获取对头数据
QDataType QueueFront(Queue* pq);
//获取对尾数据
QDataType QueueBack(Queue * pq);
//判空
bool QueueEmpty(Queue* pq);
//获取元素个数
int QueueSize(Queue* pq);

//下面实现各个接口
//初始化

//初始化
void QueueInit(Queue* pq) {
	assert(pq);
	pq->head = pq->tail= NULL;
	pq->size = 0;
}

//销毁

//销毁
void QueueDestory(Queue* pq) {
	assert(pq);
	QLNode* cur = pq->head;
	while (cur) {
		QLNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

//队尾入数据,尾插法!
//分两种情况:初始化时:head=tail=NULL;
//1.那么head为空,则直接申请节点给就行!
//2.其它,正常尾插即可!

//队尾入数据
void QueuePush(Queue* pq, QDataType x) {
	assert(pq);
	QLNode* newnode =(QLNode*)malloc(sizeof(QLNode));
	newnode->next = NULL;
	newnode->val = x;
	if (pq->head == NULL) {
		pq->head = pq->tail = newnode;
	}
	else {
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
	pq->size++;
}

//队头删数据,头删
//考虑,因为头删的话,要存下一个节点,其实最坏情况下一个节点为NULL,也就是只有一个节点,那么head能置空,tail是一个问题,因此分开写!
//1.没有节点,直接断言assert;
//2.一个节点,直接释放,给head,tail置NULL;
//3.至少两个节点:删一个,下一个肯定不问NULL,直接正常情况删除!

//队头出数据
void QueuePop(Queue* pq) {
	//头删
	assert(pq);
	//头指针为空,没有数据
	assert(pq->head);

	//一个节点
	//在单链表的头删中,可以直接写
	//在栈中特殊处理,因为一个节点的时候,要把tail置NULL
	if (pq->head->next == NULL) {
		free(pq->head);
		pq->head = NULL;
		pq->tail = NULL;
	}
	//其它
	else {
		QLNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
	pq->size--;

}

//获取队头数据

//获取队头数据
QDataType QueueFront(Queue* pq) {
	assert(pq);
	assert(pq->head);
	return pq->head->val;
}

//获取队尾数据

//获取队尾数据
QDataType QueueBack(Queue* pq) {
	assert(pq);
	assert(pq->tail);
	return pq->tail->val;
}

//判空

//判空
bool QueueEmpty(Queue* pq) {
	assert(pq);
	return pq->size == 0;
}

//获取元素个数

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

//下面为整个代码!
//Queue.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
//存储队列的数据

typedef int QDataType;

typedef struct QListNode {
	QDataType val;
	struct QListNode* next;
}QLNode;


//用结构体来存储队头,队尾,数据个数

typedef struct Queue {
	QLNode* head;
	QLNode* tail;
	int size;    //存储数据的个数
}Queue;


//初始化
void QueueInit(Queue* pq);
//销毁
void QueueDestory(Queue* pq);
//队尾入数据
void QueuePush(Queue* pq, QDataType x);
//队头出数据
void QueuePop(Queue* pq);
//获取队头数据
QDataType QueueFront(Queue* pq);
//获取队尾数据
QDataType QueueBack(Queue* pq);
//判空
bool QueueEmpty(Queue* pq);
//获取元素个数
int QueueSize(Queue* pq);

//Queue.c

#include "Queue.h"

//初始化
void QueueInit(Queue* pq) {
	assert(pq);
	pq->head = pq->tail= NULL;
	pq->size = 0;
}

//销毁
void QueueDestory(Queue* pq) {
	assert(pq);
	QLNode* cur = pq->head;
	while (cur) {
		QLNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

//队尾入数据
void QueuePush(Queue* pq, QDataType x) {
	assert(pq);
	QLNode* newnode =(QLNode*)malloc(sizeof(QLNode));
	newnode->next = NULL;
	newnode->val = x;
	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(pq->head);

	//一个节点
	//在单链表的头删中,可以直接写
	//在栈中特殊处理,因为一个节点的时候,要把tail置NULL
	if (pq->head->next == NULL) {
		free(pq->head);
		pq->head = NULL;
		pq->tail = NULL;
	}
	//其它
	else {
		QLNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
	pq->size--;

}
//获取队头数据
QDataType QueueFront(Queue* pq) {
	assert(pq);
	assert(pq->head);
	return pq->head->val;
}
//获取队尾数据
QDataType QueueBack(Queue* pq) {
	assert(pq);
	assert(pq->tail);
	return pq->tail->val;
}
//判空
bool QueueEmpty(Queue* pq) {
	assert(pq);
	return pq->size == 0;
}
//获取元素个数
int QueueSize(Queue* pq) {
	assert(pq);
	return pq->size;
}

//Test.c

#include "Queue.h"

int main() {
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);
	while (!QueueEmpty(&q)) {
		int front = QueueFront(&q);
		printf("%d ", front);
		QueuePop(&q);
	}
	return 0;
}

二、两个队列实现栈问题

1
//实现思路
//怎么入栈?
//怎么出栈?

1

//出栈:假设一个队列入 1 2 3 4,那么要求是出4,4在尾巴,怎么出,那么把1,2,3出队列,入一个空的队列,然后在出第一个队列的数据!
//入栈:如果队列不为空,则入数据

//下面实现整个接口

//创建栈

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

//动态申请创建栈

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

//入栈

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

//出栈

int myStackPop(MyStack* obj) {
    //先把不为空的队列的size-1个元素移到为空的队列
    //然后出队列
    Queue* NoEmptyQueue = &obj->q1;
    Queue* EmptyQueue = &obj->q2;
    if(QueueEmpty(&obj->q1)){
        NoEmptyQueue = &obj->q2;
        EmptyQueue = &obj->q1;
    }
    while(QueueSize(NoEmptyQueue)>1){
        int front = QueueFront(NoEmptyQueue);
        QueuePop(NoEmptyQueue);
        QueuePush(EmptyQueue,front);
    }
    int front = QueueFront(NoEmptyQueue);
    QueuePop(NoEmptyQueue);
    return front;
}

//获取栈顶数据
//这个体现接口的优势,在队列中实现了取队列尾的数据!
//直接调用

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) {
    QueueDestory(&obj->q1);
    QueueDestory(&obj->q2);
    free(obj);
}

//下面是整体的代码

typedef int QDataType;

typedef struct QListNode {
	QDataType val;
	struct QListNode* next;
}QLNode;


//用结构体来存储队头,队尾,数据个数

typedef struct Queue {
	QLNode* head;
	QLNode* tail;
	int size;    //存储数据的个数
}Queue;

//初始化
void QueueInit(Queue* pq) {
	assert(pq);
	pq->head = pq->tail= NULL;
	pq->size = 0;
}

//销毁
void QueueDestory(Queue* pq) {
	assert(pq);
	QLNode* cur = pq->head;
	while (cur) {
		QLNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

//队尾入数据
void QueuePush(Queue* pq, QDataType x) {
	assert(pq);
	QLNode* newnode =(QLNode*)malloc(sizeof(QLNode));
	newnode->next = NULL;
	newnode->val = x;
	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(pq->head);
	//一个节点
	if (pq->head->next == NULL) {
		free(pq->head);
		pq->head = NULL;
		pq->tail = NULL;
	}
	//其它
	else {
		QLNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
	pq->size--;
}
//获取队头数据
QDataType QueueFront(Queue* pq) {
	assert(pq);
	assert(pq->head);
	return pq->head->val;
}
//获取队尾数据
QDataType QueueBack(Queue* pq) {
	assert(pq);
	assert(pq->tail);
	return pq->tail->val;
}
//判空
bool QueueEmpty(Queue* pq) {
	assert(pq);
	return pq->size == 0;
}
//获取元素个数
int QueueSize(Queue* pq) {
	assert(pq);
	return pq->size;
}

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


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

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

int myStackPop(MyStack* obj) {
    //先把不为空的队列的size-1个元素移到为空的队列
    //然后出队列
    Queue* NoEmptyQueue = &obj->q1;
    Queue* EmptyQueue = &obj->q2;
    if(QueueEmpty(&obj->q1)){
        NoEmptyQueue = &obj->q2;
        EmptyQueue = &obj->q1;
    }
    while(QueueSize(NoEmptyQueue)>1){
        int front = QueueFront(NoEmptyQueue);
        QueuePop(NoEmptyQueue);
        QueuePush(EmptyQueue,front);
    }
    int front = QueueFront(NoEmptyQueue);
    QueuePop(NoEmptyQueue);
    return front;
}

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) {
    QueueDestory(&obj->q1);
    QueueDestory(&obj->q2);
    free(obj);
}

/**
 * Your MyStack struct will be instantiated and called as such:
 * MyStack* obj = myStackCreate();
 * myStackPush(obj, x);
 
 * int param_2 = myStackPop(obj);
 
 * int param_3 = myStackTop(obj);
 
 * bool param_4 = myStackEmpty(obj);
 
 * myStackFree(obj);
*/

完结!

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

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

相关文章

上海亚商投顾:沪指终结月线6连阴 北向资金净买入超160亿

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 三大指数昨日低开高走&#xff0c;沪指重新站上3000点&#xff0c;深成指、创业板指大涨超3%。半导体产业链全…

协议和序列化反序列化

“协议”和序列化反序列化 “协议”的概念&#xff1a; “协议”本身是一种约定俗成的东西&#xff0c;由通讯双方必须共同遵从的一组约定&#xff0c;因此我们一定要将这种约定用计算机语言表达出来&#xff0c;此时双方计算机才能识别约定的相关内容 我们把这个规矩叫做“…

仿真科普|CAE技术赋能无人机 低空经济蓄势起飞

喝一杯无人机送来的现磨热咖啡&#xff1b;在拥堵的早高峰打个“空中的士”上班&#xff1b;乘坐水陆两栖飞机来一场“陆海空”立体式观光……曾经只出现在科幻片里的5D城市魔幻场景&#xff0c;正逐渐走进现实。而推动上述场景实现的&#xff0c;就是近年来越来越热的“低空经…

包管理工具之npm也慌了?

起因 因为npm的种种问题,我很早就换成了pnpm和yarn(但是其实npm也在使用),已经很久没有关注npm的功能更新了。最近无意间进入Node18版本的安装目录,发现其除了常规的node,npm等默认安装了一个新的包corepack,这个就是今天我要分享的东西了。 注: 我因为18版本的node上…

Docker技术概论(3):Docker 中的基本概念

Docker技术概论&#xff08;3&#xff09; Docker 中的基本概念 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://…

MySQL 用户账号迁移

文章目录 前言1. 工具安装1.1 下载安装包1.2 编译安装 2. 用户迁移后记 前言 有一个典型的使用场景&#xff0c;就是 RDS 下云大多数都是通过 DTS 进行数据传输的&#xff0c;用户是不会同步到自建数据库的。需要运维人员在自建数据库重新创建用户&#xff0c;如果用户数量很多…

kyuubi整合spark on yarn

目录 概述实践下载配置启动 结束 概述 目标: 1.实现kyuubi spark on yarn2.实现 kyuubi spark on yarn 资源的动态分配 注意&#xff1a;版本 kyuubi 1.8.0 、 spark 3.4.2 、hadoop 3.3.6 前置准备请看如下文章 文章链接hadoop一主三从安装链接spark on yarn链接 实践 …

【音视频处理】使用ffmpeg实现多个视频合成一个视频(按宫格视图)

先上结果 环境 硬件&#xff1a;通用PC 系统&#xff1a;Windows 测试有效 软件&#xff1a;ffmpeg 解决 0、命令 ffmpeg.exe -i input1.mp4 -i input2.mp4 -i input3.mp4 -i input4.mp4 -filter_complex "[0:v]scaleiw/2:ih/2,pad2*iw:2*ih[a]; [1:v]scaleiw/2:ih/2…

看待事物的层与次 | DBA与架构的一次对话交流

前言 在计算机软件业生涯中,想必行内人或多或少都能感受到系统架构设计与数据库系统工程的重要性,也能够清晰地认识到在计算机软件行业中技术工程师这个职业所需要的专业素养和必备技能! 背景 通过自研的数据库监控管理工具,发现 SQL Server 数据库连接数在1-2K之间,想…

Java进阶-反射

来学习一下Java的反射&#xff0c;通过Class实例获取class信息的方法称为反射&#xff08;Reflection&#xff09;&#xff0c;内容如下 一、反射机制 1、概述 在运行状态中&#xff0c;对于任意一个类&#xff0c;都能够知道这个类的所有属性和方法&#xff1b;对于任意一…

UDP数据报套接字编程入门

目录 1.TCP和UDP的特点及区别 1.1TCP的特点 1.2UDP的特点 1.3区别 2.UDP Socket的api的介绍 2.1DatagramSocket API 2.2DatagramPacket API 3.回显客户端与服务器 3.1回显服务器 3.1.1UdpEchoServer类的创建 3.1.2服务器的运行方法start() 3.1.3main部分 3.1.4.完整…

LeetCode #104 二叉树的最大深度

104. 二叉树的最大深度 题目 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3 示例 2&#xff1a; 输入&#xff1a;root [1,null,2] 输出&#xff1a;2 分析 …

CMake、OpenCV 和单元测试

我写了很多关于 CMake 的文章&#xff0c;如果你感兴趣&#xff0c;可以点击以下链接阅读&#xff1a; CMake VS MakeCMake&#xff1a;在构建世界掀起风暴现代 CMake 使用技巧CMake 交叉编译CMake 生成器已开启 我们将继续对 CMake 的探索&#xff0c;这篇文章技术性高&…

云商大宗商品使用的是什么系统,有什么功能

云商大宗商品使用的系统主要包括大宗商品贸易系统、大宗商品仓储管理系统。 大宗商品贸易系统则是一种基于互联网技术的交易平台&#xff0c;旨在为买卖双方提供高效、安全、透明的交易环境。该系统具备商品管理、交易管理、资金管理、数据分析和风险管理等功能模块&#xff0…

2024年四川媒体新闻发布渠道,媒体邀约资源表

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 四川有哪些媒体新闻发布渠道&#xff0c;媒体邀约资源表&#xff1f; 2024年四川媒体新闻发布渠道&#xff0c;媒体邀约资源表 四川本地媒体&#xff1a;如四川日报、华西都市报、成都商…

2024年最好的 5 款免费的数据恢复软件

数据意外损坏或丢失&#xff1f;别担心&#xff0c;今天我为大家带来了实用的免费硬盘数据恢复软件&#xff01; 在数字化时代&#xff0c;数据的重要性不言而喻。但是&#xff0c;由于种种原因&#xff0c;数据意外损坏或丢失的情况时有发生。此时&#xff0c;一款实用的免费…

SpringBoot 自定义映射规则resultMap association一对一

介绍 例&#xff1a;学生表&#xff0c;班级表&#xff0c;希望在查询学生的时候一起返回该学生的班级&#xff0c;而一个实体类封装的是一个表&#xff0c;如需要多表查询就需要自定义映射。 表结构 班级表 学生表 SQL语句 SELECT a.id,a.name,a.classes,b.id classes…

JS(JavaScript)中如何实现,复选框checkbox多选功能

起始界面&#xff1a; 代码元素&#xff1a; <p><input type"checkbox" id"checkedAll"> 全选按钮</p><p><input type"checkbox" class"cl"> 选项1</p><p><input type"checkbox&qu…

张驰咨询:为什么每个应届生都应该参加六西格玛培训?

应届生参加六西格玛培训的现象逐渐成为了一个新的趋势&#xff0c;这背后的原因不仅仅是市场对于品质管理人才的渴求&#xff0c;也源于应届生自身发展的需求。本文张驰咨询将从应届生的视角探讨参加六西格玛培训的动机&#xff0c;以及这种培训如何为他们的职业生涯铺路。 为…

认识通讯协议——TCP/IP、UDP协议的区别,HTTP通讯协议的理解

目录 引出认识通讯协议1、TCP/IP协议&#xff0c;UDP协议的区别2、HTTP通讯协议的讲解 Redis冲冲冲——缓存三兄弟&#xff1a;缓存击穿、穿透、雪崩缓存击穿缓存穿透缓存雪崩 总结 引出 认识通讯协议——TCP/IP、UDP协议的区别&#xff0c;HTTP通讯协议的理解 认识通讯协议 …