栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列

news2025/2/28 20:12:13

文章目录

  • 队列的实现
  • 用队列实现栈
  • 用栈实现队列
  • 设计循环队列

队列的实现

这里的队列我们使用链式队列,好处就是可以很方便的取出队头的元素。
使用顺序队列取出队头元素所花费的时间复杂度为O(N),把后面的元素向前移动一个下标所花费的时间。
链式队列的存储结构:

在这里插入图片描述
在这里插入图片描述

typedef int QueueDataType;
//节点类型
typedef struct QueueNode
{
	QueueDataType data;
	struct QueueNode* next;
}QNode;
//队列类型
typedef struct Queue
{
	QNode* phead;  //头指针
	QNode* ptail;  //尾指针   使用头指针和尾指针来实现队列的删除和插入操作。
	int size;
}Que;

接口函数的实现
`

void QueueInit(Que* pq);
void QueueDestory(Que* pq);
void QueuePush(Que* pq, QueueDataType x);
void QueuePop(Que* pq);
QueueDataType QueueFront(Que* pq);
QueueDataType QueueBack(Que* pq);
int QueueSize(Que* pq);
bool QueueEmpty(Que* pq);

//实现

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

//销毁队列,这里相当于单链表的销毁,一个节点一个节点销毁
void QueueDestory(Que* pq)
{
	assert(pq);
	//删除链式队列
	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
}

//相当于单链表的尾插,先新建一个节点,初始化这个节点,尾插到队列中,这里考虑两种情况,队列为空和不为空的情况
void QueuePush(Que* pq, QueueDataType x)
{
	assert(pq);
	//新建节点
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc failed!\n");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;
	//考虑此时的队列为空
	if (pq->ptail == NULL)
	{
		assert(pq->phead == NULL);
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		//不为空时,把newnode赋值给phead->next,然后ptail = newnode
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}
//相当于单链表的头删。需要考虑两种情况,队列为空就不可以删除,队列不为空只有一个节点phead和ptail都要赋值成NULL,否则会出现ptail为野指针的情况,多个节点时,相当于单链表的头删,
void QueuePop(Que* pq)
{
	//相当于单链表的头删
	assert(pq);
	//处理队列为空的情况
	assert(!QueueEmpty(pq));
	//处理只有一个节点的情况
	if (pq->phead->next == NULL)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else   //考虑多个节点的情况
	{
		QNode* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
	pq->size--;
}
QueueDataType QueueFront(Que* pq)
{
	assert(pq);
	//处理队列为空的情况
	assert(!QueueEmpty(pq));
	return pq->phead->data;
}
//返回队列的尾部元素,这里会在用队列实现栈的时候用到
QueueDataType QueueBack(Que* pq)
{
	assert(pq);
	//处理队列为空的情况
	assert(!QueueEmpty(pq));
	return pq->ptail->data;
}
int QueueSize(Que* pq)
{
	assert(pq);
	return pq->size;
}
bool QueueEmpty(Que* pq)
{
	assert(pq);
	return pq->phead == NULL && pq->ptail == NULL;
	//return pq->size == 0;
}

用队列实现栈

leetcode做题链接在这里插入图片描述

主要思想:用两个队列来实现一个栈的功能,先进后出,后进先出的功能,我们可以这样,在不为空的队列里入数据,然后再把数据前n-1个数数据倒入另一个队列中,具体的过程用图展示:

第一步:准备两个队列,开始入数据
在这里插入图片描述
第二步:往不为空的队列里入数据,如果两个都为空,任选一个入数据
push 四次。可得队列中的数据如下图所示:
在这里插入图片描述
第三步:出数据,需要先把q1中的数据1、2、3倒入q2中,然后使用QueueBack()接口获取队尾数据4。
在这里插入图片描述
以上就是出数据和入数据的过程。
具体代码如下:

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


MyStack* myStackCreate() {
   MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
   if(obj == NULL)
   {
       perror("malloc failed!\n");
       return NULL;
   }
   QueueInit(&obj->q1);
   QueueInit(&obj->q2);

   return obj;
}

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

int myStackPop(MyStack* obj) {
    //假设为空
    Que* pEmptyQ = &obj->q1;
    Que* pNonEmptyQ = &obj->q2;
    if(!QueueEmpty(&obj->q1))
    {
        pEmptyQ = &obj->q2;
        pNonEmptyQ = &obj->q1;
    }
    //倒数据,把非空队列的数据导入空队列,剩余一个就是栈顶元素
    while(QueueSize(pNonEmptyQ)>1)
    {
        QueuePush(pEmptyQ, QueueFront(pNonEmptyQ));
        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);
    }
}

用栈实现队列

leetcode 做题链接
基本思想
使用两个栈,一个为入数据的栈,一个为出数据的栈,把数据入到入数据的栈,然后出数据到出数据的栈,基本方法如下:入队列1 2 3 4。
第一步:初始化两个栈。
在这里插入图片描述
第二步:入数据push 1 2 3 4
在这里插入图片描述
第三步:导数据到popst中
在这里插入图片描述
第四步:从popst中出数据
在这里插入图片描述
实现代码如下:

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


MyQueue* myQueueCreate() {
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    if(obj==NULL)
    {
        perror("malloc failed!\n");
        return NULL;
    }
    STInit(&obj->pushst);
    STInit(&obj->popst);
    return obj;
}

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

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

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

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

void myQueueFree(MyQueue* obj) {
    STDestory(&obj->pushst);
    STDestory(&obj->popst);
    free(obj);
}

设计循环队列

leetcode做题链接
循环队列的要点:如何用一个顺序表实现一个循环队列,front为队头,rear为队尾,判满:rear + 1 == front为满,判空:rear == front 为空。
在这里插入图片描述
第一步,初始化一个队列,k为5,n为6
在这里插入图片描述
第二步:出队列 front++;再入数据 6、7。
在这里插入图片描述
此时的rear,跑到了front的前面,我们可以 让rear % (k+1)保持rear永远不会越界front也可以使用这个公式保证front永远不会越界
在这里插入图片描述
获取队尾元素的两种方法:
在这里插入图片描述

求元素的个数的方法: (rear - front + k+1)% (k+1)

具体的实现代码如下:

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


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

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->rear+1)%(obj->k+1) == obj->front;
}
MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    if(obj == NULL)
    {
        perror("malloc failed!\n");
        return NULL;
    }
    obj->a = (int*)malloc(sizeof(int)*(k+1));
    if(obj->a == NULL)
    {
        perror("malloc failed!\n");
        return NULL;
    }
    obj->front = obj->rear = 0;
    obj->k = k;
    return obj;
}

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

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

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

}

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


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

好的我们下一篇再见。

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

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

相关文章

CentOS Linux的最佳替代方案(二)_AlmaLinux OS 8.6基础安装教程

文章目录 CentOS Linux的最佳替代方案(二)_AlmaLinux OS 8.6基础安装教程一 AlmaLinux介绍和发展历史二 AlmaLinux基础安装2.1 下载地址2.2 安装过程 三 AlmaLinux使用3.1 关闭selinux/firewalld3.2 替换默认源3.3 安装一些必要工具 CentOS Linux的最佳替…

瓶盖扫码回收APP系统 废旧物品创造价值收益

资源回收再利用是近些年国家大力倡导的,人们也在积极践行,从垃圾回收、废旧衣物回收、烟盒回收等等.....今天小白要带大家了解的是瓶盖回收APP软件开发的相关事项。瓶盖回收APP是本着资源回收的初衷,可以时间废旧瓶盖的多次利用,减…

使用Xshell服务器跑程序,用pycharm连接服务器远程开发

目标: 1.使用Xshell在服务器上创建自己项目需要的虚拟环境 2.用pycharm实现远程服务器的连接(这样就可以在本地debug或者写代码,然后再用xshell在服务器上跑) 一、使用Xshell在服务器上创建自己项目需要的虚拟环境 1.打开Xshe…

工具系列之wireshark使用说明

简介 工具下载: https://www.wireshark.org/官方FAQ: https://www.wireshark.org/faq.html 过滤器设置 通常情况下,将.pcap 数据拖拽至 wireshark中即可打开。通过: 导航栏–》分析 --> 显示过滤器 即可找到对应的筛选器,筛…

美格智能发布高性价比5G RedCap CPE解决方案SRT835,加速5G FWA商业落地

6月30日,在MWC 2023上海5G未来峰会上,美格智能重磅发布高性价比轻量化5G RedCap(也称作NR-Light)CPE解决方案SRT835。该方案搭载骁龙X35调制解调器及射频系统和WCN6856高速Wi-Fi 6解决方案,通过精简系统架构&#xff0…

【技术教程】H.265网页流媒体播放器EasyPlayer无感知播放体验优化

EasyPlayer是我们流媒体组件系列中关注度较高的产品,经过多年的发展和迭代,目前已经有多个应用版本,包括RTSP版、RTMP版、Pro版,以及js版,其中js版本作为网页播放器,受到了用户的广泛使用。 目前我们所有的…

【每天40分钟,我们一起用50天刷完 (剑指Offer)】第十天 10/50

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客,如有问题交流,欢迎评论区留言,一定尽快回复!(大家可以去看我的专栏,是所有文章的目录)   文章字体风格: 红色文字表示&#…

初探 C++ 标准库

有趣的重载 重载左移操作符,将变量或常量左移到一个对象中! C 标准库 C 标准库并不是 C 语言的一部分 C 标准库是由类库和函数库组成的集合 C 标准库中定义的类和对象都位于 std 命名空间中 C 标准库的头文件都不带 .h 后缀 C 标准库涵盖了 C 库的功…

优思学院|什么是六西格玛黑带?

六西格玛黑带,这是一个有趣的称谓。这个称号意味着拥有它的人在六西格玛方法和统计工具应用方面有很高的造诣。在企业中,只有中层以上的人才能获得这个称号。 黑带这个词源自跆拳道,因为跆拳道最高段位的人所戴的腰带是黑色的。后来&#xf…

『赠书活动 | 第十三期』《算力经济:从超级计算到云计算》

💗wei_shuo的个人主页 💫wei_shuo的学习社区 🌐Hello World ! 『赠书活动 | 第十三期』 本期书籍:《算力经济:从超级计算到云计算》 赠书规则:评论区:点赞|收…

多个el-checkbox-group复选框组 选项互斥

需求 多个el-checkbox-group复选框组 , 组与组之间的选项是互斥的效果效果 代码实现 template <template><div class"page"><el-checkbox-groupv-for"(item, index) in list"v-model"item.checked":key"index"chan…

网络投票链接的制作方法投票制作方法微网络投票

用户在使用微信投票的时候&#xff0c;需要功能齐全&#xff0c;又快捷方便的投票小程序。 而“活动星投票”这款软件使用非常的方便&#xff0c;用户可以随时使用手机微信小程序获得线上投票服务&#xff0c;很多用户都很喜欢“活动星投票”这款软件。 “活动星投票”小程序在…

docker-compose部署Minio

一、镜像选择 Minio有很多镜像会有一些bug&#xff0c;而且不好解决&#xff0c;这里使用的是镜像 RELEASE.2021-04-18T19-26-29Z 直接: docker pull minio/minio:RELEASE.2021-04-18T19-26-29Z 即可&#xff1a; 拉取之后可以打个tag&#xff0c;这里是new2 RELEASE.2021…

在chrome-console中进行xpath/css/js定位(六)

目录 1.xpath 1.1 绝对定位与相对定位 1.2 通配符与不包含筛选 1.3 Xpath函数运算的简单实用 1.4 各种亲戚标签的定位 1.5xpath实例 1.5.1xpath:属性定位 1.5.2xpath:其它属性 1.5.3xpath:标签 1.5.4xpath:层级 1.5.5xpath:索引 1.5.6xpath:逻辑运算 1.5.7xpath:模…

界面组件DevExpress WPF v23.1新版亮点 - 启动和内存优化

DevExpress WPF拥有120个控件和库&#xff0c;将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序&#xff0c;这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 无论是Office办公软件…

智能机井灌溉控制器批量应用于新疆农业灌溉计量监测项目

近日&#xff0c;新疆某县级水利部门为进一步提升水资源取用水的监管能力&#xff0c;完善水资源实时监控、计划用水和节约用水管理目标&#xff0c;对该地农业灌溉用水计量设施进行升级改造&#xff0c;将700口井安装智能机井灌溉控制器&#xff0c;有效实现水量监测&#xff…

node.js通过node-java库调用java接口(jar包)

node.js通过node-java库调用java接口 1、业务需要2、开发环境3、调用java包简单实例4、调用自定的jar包接口 1、业务需要 最近因项目需求&#xff0c;需要调用第三方java的打的jar包&#xff0c;但项目后端是用node.js写的&#xff0c;因此需要用node.js调用第三方jar,网上搜集…

如何让其他电脑连接自己电脑上的虚拟机

想使用电脑A连接电脑B中的虚拟机有两种方式(这里说的都是windows环境,并且都在A和B在同一网络环境下) 方式一 通过配置windows防火墙中的入站规则,以开放端口的形式访问,但是这种方式电脑A中没法配置电脑B中虚拟机的域名映射.方式二 通过更改虚拟机的网络连接模式,并且要修改虚…

爬虫入门指南(2):如何使用正则表达式进行数据提取和处理

文章目录 正则表达式正则表达式中常用的元字符和特殊序列案例 使用正则表达式提取数据案例存储数据到文件或数据库使用SQLite数据库存储数据的示例代码SQLite基本语法创建表格&#xff1a;插入数据&#xff1a;查询数据&#xff1a;更新数据&#xff1a;删除数据&#xff1a;条…

尚硅谷Docker实战教程-笔记05【本地镜像发布到阿里云与私有库】

尚硅谷大数据技术-教程-学习路线-笔记汇总表【课程资料下载】视频地址&#xff1a;尚硅谷Docker实战教程&#xff08;docker教程天花板&#xff09;_哔哩哔哩_bilibili 尚硅谷Docker实战教程-笔记01【理念简介、官网介绍、平台入门图解、平台架构图解】尚硅谷Docker实战教程-笔…