队列的相关操作:用队列实现栈

1.思路解析

由于C语言封装度不是很高,不像C++可以直接用现成的,所以我们要自己做一个“轮子”,即自己实现一个队列,这里直接放出代码,详解可以移步到我的另一篇关于队列的博客,点我移步,原题来源于leetcode里面的用队列实现栈。

typedef int QDataType;

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

typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

void QueueDestroy(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);

		cur = next;
	}

	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

// 队尾插入
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);

	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}

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

	if (pq->ptail == NULL)
	{
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}

	pq->size++;
}

// 队头删除
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->size != 0);

	/*QNode* next = pq->phead->next;
	free(pq->phead);
	pq->phead = next;

	if (pq->phead == NULL)
		pq->ptail = NULL;*/

		// 一个节点
	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--;
}

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->phead);

	return pq->phead->val;
}

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->ptail);

	return pq->ptail->val;
}


int QueueSize(Queue* pq)
{
	assert(pq);

	return pq->size;
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->size == 0;
}

注意:核心要点就是在操作时不管插入元素还是取出元素然后删除,都要判断空与非空队列,例如取元素就要将非空队列元素转移到空队列,然后将存留的栈顶元素删除即可;插入元素要插入到非空队列,始终保持一个空队列与一个非空队列。

2. 实现栈后的相关操作

2.1 初始化

初始化时要注意不能使用局部变量,因为局部变量出函数就会被销毁,所以要使用动态内存申请

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


MyStack* myStackCreate() 
{
    //局部变量出函数会被销毁,所以使用malloc不会被销毁
    MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
    //C语言中'->'优先级大于'&',可以不加内部括号
    QueueInit(&(pst->q1));
    QueueInit(&(pst->q2));
    return pst;
}

 2.2 插入元素

前面我们知道了要向非空队列插入元素,所以要先判断空队列与非空队列再进行插入元素。

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

2.3 删除元素

删除元素首先将非空队列中除栈顶元素转移到空队列中,然后对栈顶元素进行删除,这里判断空队列与非空队列使用了假设法,即先假设一种情况,假设成功直接进行下一步删除操作,反之将原来假设的情况置反,最后题目要求返回栈顶元素,所以使用QueueFront找到栈顶元素后返回。

int myStackPop(MyStack* obj) 
{
    //将不为空的队列前size-1个数据转移到另一个,删除留下来的栈顶数据
    //假设法
    Queue* empty = &(obj->q1);
    Queue* 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;
}

2.4 取出栈顶元素

同样需要判断空队列与非空队列,对非空队列进行取出栈顶元素的操作。

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

2.5 判空与释放

这里不能直接使用free(obj)进行释放,因为obj的结构如图,只释放obj这个"大哥",那么他的"小弟",p1和p2就会导致内存泄漏,所以要先销毁p1和p2然后对obj进行释放即可。

bool myStackEmpty(MyStack* obj) 
{
    //两个队列同时为空才为空
    return QueueEmpty(&(obj->q1)) && QueueEmpty(&(obj->q2)); 
}

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

    free(obj);
}
 

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

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

相关文章

Mp3tag for Mac:音乐标签,轻松管理

还在为杂乱无章的音乐文件而烦恼吗?Mp3tag for Mac,让您的音乐库焕然一新!它支持多种音频格式,批量编辑标签,让音乐管理变得简单高效。同时,自动获取在线数据库的音乐元数据,确保您的音乐库始终…

并发-判断线程对象是否处于活动状态 - isAlive

t.isAlive() 测试线程t是否处于活动状态,只要线程启动并且没有终止,方法返回值就是truestart()之前,线程不处于活动状态,之后就处于活动状态示例:运行结果:但是事情并没有这么简单,先来看一下以…

面试经典算法系列之数组/字符串5 -- 反转字符串中的单词

面试经典算法题37-反转字符串中的单词 LeetCode.151 公众号:阿Q技术站 问题描述 给你一个字符串 s ,请你反转字符串中 单词 的顺序。 单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。 返回 单词 顺序颠倒且 单词…

【JavaEE 初阶(五)】文件操作和IO

❣博主主页: 33的博客❣ ▶️文章专栏分类:JavaEE◀️ 🚚我的代码仓库: 33的代码仓库🚚 🫵🫵🫵关注我带你了解更多文件操作 目录 1.前言2.认识文件3.文件操作3.1File 属性3.2构造方法3.3File类方法 4.文件内容操作4.1R…

栈和队列的相互实现

1. 两个队列实现栈. - 力扣(LeetCode) 队列的特点是先进先出,而栈的特点是后进先出(先进后出),也就是说重点在于利用两个队列来改变“出”的顺序。 假设我们在进行入栈操作的时候将数据依次入到一个队列中…

国产操作系统下Chrome的命令行使用 _ 统信 _ 麒麟

原文链接:国产操作系统下Chrome的命令行使用 | 统信 | 麒麟 Hello,大家好啊!今天我们来聊聊如何在国产操作系统上使用命令行操作Google Chrome。无论是进行自动化测试、网页截图还是网页数据抓取,使用命令行操作Google Chrome都能…

LVS的三种工作模式---(DR/TUN/NAT)

目录 一、NAT模式(LVS-NAT) 二、IP隧道模式(LVS-TUN) 三、DR模型--直接路由模式(LVS-DR) LVS/DR模式ARP抑制 原因: LVS的DR工作模式及配置: LVS的NAT工作模式及配置&#xff1…

Python游戏制作大师,Pygame库的深度探索与实践

写在前言 hello,大家好,我是一点,专注于Python编程,如果你也对感Python感兴趣,欢迎关注交流。 希望可以持续更新一些有意思的文章,如果觉得还不错,欢迎点赞关注,有啥想说的&#x…

ppt图片居中对齐

今天简单尝试了一下ppt图片怎么居中对齐,记录如下 准备一张图片 可以把位置该成居中 就可以让图形居中了

完全背包问题(c++)

完全背包问题 当前有 N 种物品,第 i 种物品的体积是 ci​,价值是 wi​。 每种物品的数量都是无限的,可以选择任意数量放入背包。 现有容量为 V 的背包,请你放入若干物品,使总体积不超过 V,并且总价值尽可…

7. path路径绘制:使用path绘制曲线

曲线在SVG中通常是通过贝塞尔曲线命令来绘制的,包括二次贝塞尔曲线(Q)和三次贝塞尔曲线(C)。这些命令允许我们创建平滑的曲线路径。 贝塞尔曲线的原理 贝塞尔曲线的基本原理是通过控制点和锚点来定义一条曲线的形状。…

Android的视图显示和管理机制:layout view window WindowManager Canvas Surface

在Android系统中,Layout view window WindowManager Canvas Surface SurfaceFlinger这些组件协同工作,以实现图形的绘制和显示。需要搞明白这些组件是什么时候创建的以及他们之间的结构关系。 从上到下的层级关系:用户在View上进行操作&…

数据结构复习指导之树、森林

文章目录 树、森林 考纲内容 复习提示 1.树的存储结构 1.1双亲表示法 1.2孩子表示法 1.3孩子兄弟表示法 2.树、森林、与二叉树的转换 2.1树转换为二叉树 2.2森林转换为二叉树 2.3二叉树转换为森林 3.树和森林的遍历 3.1树的遍历 3.2森林的遍历 树、森林 考纲内容…

手机电脑通用便签推荐 好用便签下载

便签软件作为一种日常记录和管理工具,其实用性和便捷性深受用户喜爱。一款优秀的便签软件不仅能帮助我们随时随地记录重要信息,还能有效提高工作效率。然而,市场上很多便签应用仅限于单一平台使用,对于需要在手机和电脑间频繁切换…

FPGA第1篇,FPGA现场可编程门阵列,从0开始掌握可编程硬件开发(FPGA入门指南)

简介:FPGA全称Field-Programmable Gate Array,是一种可编程逻辑器件,它通过可编程的逻辑单元和可编程的连接网络实现了灵活的硬件实现。与固定功能的集成电路(ASIC)相比,FPGA具有更高的灵活性和可重新配置性…

python随机显示四级词汇

python实现一个浮动窗口随机显示四级单词在桌面跑来跑去 实现一个浮动窗体随机显示四级单词在windows桌面置顶移动 tkinter库来创建窗口和显示单词,以及random库来随机选择单词。 使用after方法来定时更新窗口的位置,实现单词窗口的慢慢移动效果 使用…

day10-Map集合

Map 1.Map 1.1 Map简介 1.为什么使用Map集合 购物车提供的四个商品和购买的数量在后台需要容器存储。 每个商品对象都一一对应一个购买数量。 把商品对象看成是Map集合的键,购买数量看成Map集合的值。 例如: {商品12 , 商品23 , 商品3 2 , 商品4…

GitHub操作

远程库-GitHub GitHub网址 GitHub是全球最大的远程库 1. 创建远程库 2. 远程仓库操作 2.1 创建远程仓库别名 git remote -v 查看当前所有远程库地址别名 git remote add 别名 远程地址 设置远程库地址别名 案例操作 起一个别名会出现两个别名,是因为既可以拉取…

第二步->手撕spring源码之bean操作

本步骤目标 本步骤继续完善 Spring Bean 容器框架的功能开发,在这个开发过程中会用到较多的接口、类、抽象类,它们之间会有类的实现、类的继承。 这一次我们把 Bean 的创建交给容器,而不是我们在调用时候传递一个实例化好的 Bean 对象&#x…

vue3使用setup模式的store报错

** setup store模式 $reset方法报错 ** 顾名思义就是 使用store 使用的是setup 语法模式 不能执行$reset 方法 解决方式: // main.ts import { createPinia } from pinia const pinia createPinia() pinia.use(({ store }) > {const initialState JSON.pars…
最新文章