队列实现栈(你看我讲的是不是最细的就完了)

这篇具有很好参考价值的文章主要介绍了队列实现栈(你看我讲的是不是最细的就完了)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

最伟大的成就往往起源于最强烈的热情。                   -- 诺曼·文森特·皮尔
目录

🗼一.队列实现栈

🍅二.使用两个队列来模拟实现栈

🍋1.栈结构体包含两个队列 

🍒2.创建一个结构体的指针 

🍂3.myStackPush入栈操作

🌺4.myStackPop出队列操作并返回剩下的一个元素,也就是栈顶的元素

🍁5.myStackTop返回栈顶的元素

☘️6.myStackEmpty判断空

🌳7. myStackFree释放模拟的栈

🍑三.完整代码



题目描述:
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppop 和 empty)。
实现 MyStack 类:

void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

 

示例:

输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]

解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False

注意:这里myStack.pop()和myStack.top()都是先保存栈顶的元素,然后再返回栈顶的元素,只是myStack.pop()还要删除栈顶的元素。所以上述的解释为啥这两个函数返回的都是2,就是这个原因。一定要理解上述的MyStack类的函数,才能后续更好的写代码。
还有一个队列实现栈的,大家可以自行下去试试手。
做题链接:队列实现栈

🗼一.队列实现栈

🍅二.使用两个队列来模拟实现栈

思路讲解:我们使用两个队列来回倒数据,利用队列先进先出的性质,每次等一个队列往另一个队列倒数据还剩下一个时,这便是队列的尾,也就是栈的头了。不清楚?没关系啊,老样子画图理解:
队列实现栈(你看我讲的是不是最细的就完了)

创建好两个栈了,关键就是如何实现栈的功能? 
队列实现栈(你看我讲的是不是最细的就完了)
这时我们把队列1的前4个数据往队列2里面入数据,然后剩下的5就是栈顶的元素了,直接pop掉即可,因为这符合栈的数据后进先出的规则,出的数据就是队列1剩下的5。
队列实现栈(你看我讲的是不是最细的就完了)

思路还是比较简单的,具体就要看如何写代码: 
先大致看一下接口函数:

typedef struct {

} MyStack;


MyStack* myStackCreate() {

}

void myStackPush(MyStack* obj, int x) {

}

int myStackPop(MyStack* obj) {

}

int myStackTop(MyStack* obj) {

}

bool myStackEmpty(MyStack* obj) {

}

void myStackFree(MyStack* obj) {

}

🍋1.栈结构体包含两个队列 

typedef struct {//栈结构体包含两个队列
  Queue q1;//队列1
  Queue q2;//队列2
} MyStack;

🍒2.创建一个结构体的指针 

平常我们写栈和队列的时候,都是定义一个结构体的变量,然后使用传结构体变量的地址,也就是传参的方式,但是今天这个接口函数是使用的返回值的形式,我们要注意。

MyStack* myStackCreate() 
{
  MyStack*obj=(MyStack*)malloc(sizeof(MyStack));//创建一个结构体的指针
  if(obj==NULL)
  return NULL;
  QueueInit(&obj->q1);//初始化队列1
  QueueInit(&obj->q2);//初始化队列2
  return obj;//返回结构体的指针
}

🍂3.myStackPush入栈操作

入栈开始我们画图就说了,也就是这里的入队列,第一次两个队列都为空,然后随便往哪个队列入数据即可。

void myStackPush(MyStack* obj, int x) {
   if(!QueueEmpty(&obj->q1))
   //这里是队列1尾非空,那么就是队列1有数据了,那就继续入数据
   {
        QueuePush(&obj->q1,x);
   }
   else//这里就是当队列1为空时,那么队列2为空或者不为空,那么都往队列2入数据
   {
        QueuePush(&obj->q2,x);
   }
}

🌺4.myStackPop出队列操作并返回剩下的一个元素,也就是栈顶的元素

这个函数就是开始倒数据了,把一个队列的数据倒到另一个队列里面去,然后队列还剩下一个没倒过去的数据,这个就是栈顶的元素,返回栈顶的元素,然后删除栈顶的元素。

int myStackPop(MyStack* obj)
{
    Queue*pEmpty=&obj->q1;//这时我们不知道那个队列是空的,这里我们假设队列1为空
    Queue*pNonEmpty=&obj->q2;
    if(!QueueEmpty(pEmpty))
    {
        pEmpty=&obj->q2;//如果我们假设错误,就交换一下即可
        pNonEmpty=&obj->q1;
    }
       while(QueueSize(pNonEmpty)>1)//QueueSize是队列里面的函数,求此时队列元素的个数
       {                        //这里因为我们需要返回剩下的一个元素,所以循环条件为大于1
          QueuePush(pEmpty,QueueFront(pNonEmpty));//把队列头的元素依次往另一个队列里面倒
          QueuePop(pNonEmpty);//然后依次pop出这个队列的元素
       }
       int top=QueueFront(pNonEmpty);//这就是剩下的那个元素
       QueuePop(pNonEmpty);
       return top;
}

🍁5.myStackTop返回栈顶的元素

这个实现就非常简单了,上面的pop函数其实差不多都已经实现了。文章来源地址https://www.toymoban.com/news/detail-459879.html

int myStackTop(MyStack* obj)
{
     if(!QueueEmpty(&obj->q1))//如果队列1不为空,返回队列尾的元素
       return QueueBack(&obj->q1);//也就是剩下的那个元素,也就是栈顶的元素
     else
       return QueueBack(&obj->q2);
}

☘️6.myStackEmpty判断空

bool myStackEmpty(MyStack* obj) 
{
  return QueueEmpty(&obj->q1)//两个队列都为空时,栈也就为空了,所以使用逻辑符且
     &&QueueEmpty(&obj->q2);
}

🌳7. myStackFree释放模拟的栈

void myStackFree(MyStack* obj) 
{
  QueueDestroy(&obj->q1);//销毁队列1和2
  QueueDestroy(&obj->q2);
  free(obj);//再释放栈的结构体指针
}

🍑三.完整代码

typedef int QDataType;
typedef struct QListNode
{
	struct QListNode* next;
	QDataType data;
}QNode;

// 队列的结构 
typedef struct Queue
{
	QNode* front;
	QNode* rear;
	int size;
}Queue;

// 初始化队列 
void QueueInit(Queue* q);
// 队尾入队列 
void QueuePush(Queue* q, QDataType x);
// 队头出队列 
void QueuePop(Queue* q);
// 获取队列头部元素 
QDataType QueueFront(Queue* q);

// 获取队列队尾元素 
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数 
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q);
// 销毁队列 
void QueueDestroy(Queue* q);

void QueueInit(Queue* q)
{
	assert(q);
	q->front=NULL;
    q->rear = NULL;
    q->size=0;
}

// 队尾入队列 
void QueuePush(Queue* q, QDataType x)
{
	assert(q);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc\n");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;
	//当只要一个结点
	if (q->rear == NULL)
	{
		q->rear = q->front = newnode;
	}
	//当有两个结点的时候
	else
	{
		q->rear->next = newnode;
		q->rear = newnode;
	}
	q->size++;
}
// 队头出队列 
void QueuePop(Queue* q)
{
	assert(q);
	assert(q->front);
	//当只要一个结点时
	if (q->front->next == NULL)
	{
		free(q->front);
		q->front = q->rear = NULL;
	}
	else//当有两个及两个以上的结点的时候
	{
		Queue* next = q->front->next;
		free(q->front);
		q->front = NULL;
		q->front = next;
	}
	q->size--;
}

// 获取队列头部元素 
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	return q->front->data;
}

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q)
{
	assert(q);
	return q->front == NULL
		&& q->rear == NULL;
}

// 销毁队列 
void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* cur = q->front;
	while (cur)
	{
		Queue* next = cur->next;
		free(cur);
		cur = NULL;
		cur = next;
	}
	q->front = q->rear = NULL;
}

// 获取队列中有效元素个数 
int QueueSize(Queue* q)
{
	assert(q);
	return q->size;
}
// 获取队列队尾元素 
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(q->rear);
	return q->rear->data;
}

typedef struct {//栈结构体包含两个队列
  Queue q1;//队列1
  Queue q2;//队列2
} MyStack;


MyStack* myStackCreate() 
{
  MyStack*obj=(MyStack*)malloc(sizeof(MyStack));//创建一个结构体的指针
  if(obj==NULL)
  return NULL;
  QueueInit(&obj->q1);//初始化队列1
  QueueInit(&obj->q2);//初始化队列2
  return obj;//返回结构体的指针
}

void myStackPush(MyStack* obj, int x) {
   if(!QueueEmpty(&obj->q1))
   //这里是队列1尾非空,那么就是队列1有数据了,那就继续入数据
   {
        QueuePush(&obj->q1,x);
   }
   else//这里就是当队列1为空时,那么队列2为空或者不为空,那么都往队列2入数据
   {
        QueuePush(&obj->q2,x);
   }
}

int myStackPop(MyStack* obj)
{
    Queue*pEmpty=&obj->q1;//这时我们不知道那个队列是空的,这里我们假设队列1为空
    Queue*pNonEmpty=&obj->q2;
    if(!QueueEmpty(pEmpty))
    {
        pEmpty=&obj->q2;//如果我们假设错误,就交换一下即可
        pNonEmpty=&obj->q1;
    }
       while(QueueSize(pNonEmpty)>1)//QueueSize是队列里面的函数,求此时队列元素的个数
       {                            //这里因为我们需要返回剩下的一个元素,所以循环条件为大于1
           QueuePush(pEmpty,QueueFront(pNonEmpty));//把队列头的元素依次往另一个队列里面倒
           QueuePop(pNonEmpty);//然后依次pop出这个队列的元素
       }
       int top=QueueFront(pNonEmpty);//这就是剩下的那个元素
       QueuePop(pNonEmpty);
       return top;
}

int myStackTop(MyStack* obj)
{
     if(!QueueEmpty(&obj->q1))//如果队列1不为空,返回队列尾的元素
       return QueueBack(&obj->q1);//也就是剩下的那个元素,也就是栈顶的元素
     else
       return QueueBack(&obj->q2);
}

bool myStackEmpty(MyStack* obj) 
{
  return QueueEmpty(&obj->q1)//两个队列都为空时,栈也就为空了,所以使用逻辑符且
     &&QueueEmpty(&obj->q2);
}

void myStackFree(MyStack* obj) 
{
  QueueDestroy(&obj->q1);//销毁队列1和2
  QueueDestroy(&obj->q2);
  free(obj);//再释放栈的结构体指针
}

到了这里,关于队列实现栈(你看我讲的是不是最细的就完了)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 人脸检测是不是目标检测呢?

    人脸检测是不是目标检测呢? 人脸识别和目标检测都是计算机视觉领域的重要应用之一,但它们的应用场景和方法有所不同。 人脸识别是一种通过计算机技术对照片、视频等图像中的人脸进行识别的技术。人脸识别一般分为两个步骤: 人脸检测和人脸识别 。人脸检测是指在

    2024年02月06日
    浏览(40)
  • 【C语言】判断是不是闰年

    闰年的判断方法(两个条件都满足): 1)年份能被4整除 ,但不能被100整除。 2)年份能被400整除。 输入一个年份,判断它是不是闰年  我们可以利用bool或者_Bool的返回值来判断是否为闰年(bool(布尔类型)是一种数据类型,只有真(true)和假(false)两个值) 判断1000~2

    2024年02月06日
    浏览(37)
  • 如何辨别ChatGPT是不是真的

    随着ChatGPT爆红,国内陆续出现了几个所谓的“ChatGPT 反向代理站点”,乍一试回答似乎还挺靠谱,但它们真的是ChatGPT吗?本文以其中一个站点为例,对其真伪进行辨别。 其实最多只需要问两个问题,基本上就可以做出判断了。 1.你是谁? 2.列举两条2023年发生的新闻   而Ch

    2024年02月11日
    浏览(33)
  • PostgreSQL 是不是大小写敏感

    如果你踩过 MySQL 的大坑的话就知道:MySQL 在 Windows 下不区分大小写,但在 Linux 下默认是区分大小写。 如果你稍加不注意就会出现在本机开发的程序运行一切正常,发布到服务器行就出现表名找不到的问题。 这是我们前一个项目遇到的巨大问题,开发是在 Windows 下进行,但是

    2024年01月25日
    浏览(38)
  • AIGC是不是有点虎头蛇尾

    一、前言 2023年上半年AI与AIGC真是风风火火,不管是技术界还是资本界还是其他任何领域,如果你不知道chatgpt和AIGC,你就是个跟不上时代的人儿。如今大半年过去了,好像这个chatgpt和AIGC比没有太多的人提起,是不是有点虎头蛇尾了呢。了解本博主的人应该知道,本博主并不

    2024年02月09日
    浏览(35)
  • bash: 睡觉的冒号;是不是两个点?

    在bash里冒号和躺着的冒号的用法不一样一定要注意别用错。 难道正常的不是两个点)的作用: A sequence expression takes the form {x…y[…incr]}, where x and y are either integers or single characters, and incr, an optional increment, is an integer. When integers are supplied, the expression expands to each number between x

    2024年02月15日
    浏览(32)
  • 3DTile是不是没有坐标的选择?

    可参考以下内容: 一、坐标参考系统(CRS) 3D Tiles 使用右手笛卡尔坐标系;也就是说,x和y的叉积产生z。3D Tiles 将z轴定义为局部笛卡尔坐标系的向上。tileset的全局坐标系通常位于WGS 84地心固定(ECEF)参考系(EPSG4978)中,但它不是必须的,例如,发电厂可以在其本地完全定义用于没

    2024年02月22日
    浏览(34)
  • 程序员未来是不是会大量失业?

    程序员宝藏库 :https://gitee.com/sharetech_lee/CS-Books-Store 会,但是主要原因并不是来自最近爆火的AIGC。 生成式AI对比与传统的工具的确很强大,但是要说替代某种工作岗位还为时尚早。最近铺天盖地的相关推文,热度一波未平又起一波,想想前两年的元宇宙、web3就知道,这背后

    2023年04月10日
    浏览(33)
  • Java判断一个实体是不是空的

    在Java中,我们可以使用以下方法来判断一个实体是否为空: 对象是否为null 可以使用Java中的 == 运算符来判断一个对象是否为null,如果对象为null,则表示对象为空。 例如: 字符串是否为空 可以使用Java中的 isEmpty() 方法来判断一个字符串是否为空,如果字符串为空,则返回

    2024年02月13日
    浏览(36)
  • 如何查看自己的网卡是不是千兆网卡

    1、打开自己的设备管理器 2、打开网络适配器 3、右键自己的网卡(第二个) 4、 选择属性,再选择\\\"高级\\\"选项

    2024年02月11日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包