队列实现栈与栈实现队列

news2024/11/15 16:28:47

文章目录

  • 前言
  • 一、使用队列实现栈
  • 二、使用栈实现队列


前言

1、用于巩固栈和队列。
2、本章是使用纯C语言实现的栈和队列,不懂的可以先看看这个喔:c语言实现栈和队列,当然这里直接用C++的栈和队列会更方便哦。
3、利于复习C语言的知识点。

一、使用队列实现栈

1·、题目链接:用队列实现栈
2、题目描述:

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

3、例子:
在这里插入图片描述
4、题目分析:

(1)队列的操作是先进先出并且队头出,队尾进,而栈相反是先进后出,栈顶出,栈顶入
(2)题目要求我们使用两个队列来实现这个栈的一些操作,如:push,pop等。 我们可以使用两个队列进行倒数据:
(3)进栈:将数据储存到有数据的队列里队尾(要是两个队列都为空的话随便进一个就行喔)
(4)出栈:将有数据的队列往没有数据的队列里倒,直到剩下一个数据之后停止倒数据,进行队列的出队操作即可将最后进的数据删除(也就是出栈)。
(5)取栈顶元素:查看有数据队列的队头即可。 (6)判断栈是否为空:即判断两个队列是否为空即可,两个队列为空栈就为空,不然就是不为空。

5、图解:
进栈:
在这里插入图片描述
出栈:
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/b9c9ef27c88b445ba0d12f329af7451f.png

6、参考代码:

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 data);
// 队头出队列 
void QueuePop(Queue* q);
// 获取队列头部元素 
QDataType QueueFront(Queue* q);
// 获取队列队尾元素 
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数 
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
bool QueueEmpty(Queue* q);
// 销毁队列 
void QueueDestroy(Queue* q);

// 初始化队列 
void QueueInit(Queue* q)
{
	q->_front = NULL;
	q->_rear = NULL;
	q->size = 0;
}

// 队尾入队列 
void QueuePush(Queue* q, QDataType data)
{
	assert(q);
	//生成节点
	QNode* tmp = (QNode*)malloc(sizeof(QNode));
	if (tmp == NULL)
	{
		perror("err");
		return;
	}
	tmp->_data = data;
	tmp->_next = NULL;
	//没有节点
	if (q->_front ==NULL)
	{
		q->_front = q->_rear = tmp;
	}
	//有节点
	else
	{
		 q->_rear->_next=tmp;
		 q->_rear = tmp;
	}
	q->size++;
}

// 队头出队列 
void QueuePop(Queue* q)
{
	assert(q);
	//队列为空
	assert(q->_front);
	//队列只有一个元素或多个元素
	if (q->_front == q->_rear)
	{
		q->_front = q->_rear = NULL;
	}
	else
	{
		QNode* next = q->_front->_next;
		free(q->_front);
		q->_front = next;
	}
	q->size--;
}

// 获取队列头部元素 
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(q->_front);
	return q->_front->_data;
}

// 获取队列队尾元素 
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(q->_rear);
	return q->_rear->_data;
}

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

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

// 销毁队列 
void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* tmp = q->_front;
	while (tmp!=NULL)
	{
		QNode* next = tmp->_next;
		free(tmp);
		tmp = next;
	}
	q->_front=q->_rear= NULL;
	q->size = 0;
}

//栈的结构体,因为通过两个队列来实现,所以成员为2个队列
typedef struct {
    Queue  q1;
    Queue  q2;
} MyStack;



/
//主要部分在下面,上面的是队列




//初始化栈
MyStack* myStackCreate() {
    //动态申请一个栈,如果直接创建 MyStack st 的话,这个栈会随着函数销毁而销毁,但是动态申请就不会
    MyStack *st=(MyStack*)malloc(sizeof(MyStack));
    //初始化两个队列
    QueueInit(&st->q1);
    QueueInit(&st->q2);
    return st;
}

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


//出栈
int myStackPop(MyStack* obj) {
     //将不为空的队列往空的队列倒,直到只剩下一个元素
     //假设p1是为空的队列 
     Queue *p1=&obj->q1;
     Queue *p2=&obj->q2;
     //假设不成立进行修正
     if(!QueueEmpty(p1))
     {
         p1=&obj->q2;
         p2=&obj->q1;
     }

     //倒数据
     while(QueueSize(p2)>1)
     {
          QueuePush(p1,QueueFront(p2));
          QueuePop(p2);
     }
     //先将最后一个保存再弹出
       int tmp=QueueBack(p2);
         QueuePop(p2);
         return tmp;
    
}

//取栈顶的元素
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) {
    //先将两个队列销毁,再销毁栈,顺序不能乱,如果先销毁栈的话就找不到队列了,
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    free(obj);
    obj=NULL;
}

二、使用栈实现队列

1、题目链接:栈实现队列
2、题目描述:

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):

实现 MyQueue 类:

void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek()返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false

3、例子:
在这里插入图片描述
4、题目分析:

(1)通过两个栈来实现队列的push、pop等操作。
(2)我们可以固定一个栈(sta1)保存数据(进行入队操作),另一个栈(sta2)来进行展现队头数据和出队头的操作,当要展现队头数据和出队头的操作时,如果sta2为不空的话就展示栈顶的元素或者出栈,当sta2为空时就将sta1的数据倒到sat2里,再进行不为空的操作。
(3)取队头元素:直接取sta2的栈顶数据,(如果sta2为空的话就要将sta1的数据倒到sta2再取)
(4)判断队列是否为空:通过判断两个栈是否存在元素来判断是否为空,两个都为空即为空。

5、图解:
在这里插入图片描述
6、参考代码:

typedef int STDataType;
typedef struct Stack
{
	STDataType* _a;
	int _top;		// 栈顶
	int _capacity;  // 容量 
}Stack;
// 初始化栈 
void StackInit(Stack* ps);
// 入栈 
void StackPush(Stack* ps, STDataType data);
// 出栈 
void StackPop(Stack* ps);
// 获取栈顶元素 
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数 
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool StackEmpty(Stack* ps);
// 销毁栈 
void StackDestroy(Stack* ps);

// 初始化栈 
void StackInit(Stack* ps)
{
    assert(ps);
    ps->_capacity = 0;
    ps->_a = NULL;
    ps->_top = 0;
}

// 入栈 
void StackPush(Stack* ps, STDataType data)
{
    //满了扩容
    if (ps->_capacity == ps->_top)
    {
        int size = 0;
        if (ps->_capacity == 0)
        {
                 size = 4;
        }
        else
        {
            size = ps->_capacity * 2;
        }
        STDataType* tmp = (STDataType*)realloc(ps->_a, sizeof(STDataType) * size);
        //判断
        if (tmp == NULL)
        {
            perror("err");
            return ;
        }
        ps->_a = tmp;
        ps->_capacity = size;
    }
    //入栈
    ps->_a[ps->_top] = data;
    ps->_top++;
}

// 获取栈顶元素 
STDataType StackTop(Stack* ps)
{
    assert(ps);
    assert(ps->_top);
    return ps->_a[ps->_top - 1];
}

// 出栈 
void StackPop(Stack* ps)
{
    assert(ps);
    //栈为空 
    assert(ps->_top);
    ps->_a[ps->_top - 1] = 0;
    //栈不为空
    ps->_top--;
}

// 获取栈中有效元素个数 
int StackSize(Stack* ps)
{
    assert(ps);
    return ps->_top;
}

// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool StackEmpty(Stack* ps)
{
    assert(ps);
    return ps->_top == 0;
}

// 销毁栈 
void StackDestroy(Stack* ps)
{
    assert(ps);
    free(ps->_a);
    ps->_a = NULL;
    ps->_capacity = 0;
    ps->_top = 0;
}





//
//下面是主要部分,上面是栈





typedef struct {
    //存数据
     Stack sta1;
    //倒数据
     Stack sta2;
} MyQueue;

//初始化队列
MyQueue* myQueueCreate() {
    MyQueue* tmp=(MyQueue*)malloc(sizeof(MyQueue));
    //初始化两个栈
    StackInit(&tmp->sta1);
    StackInit(&tmp->sta2);
    //返回队列
      return tmp;
}
//进队
void myQueuePush(MyQueue* obj, int x) {
   //压进储存数据的sta1
    StackPush(&obj->sta1,x);
}

int myQueuePop(MyQueue* obj) {
    //sta2为空就倒数据
    int tmp=0;
    if(StackEmpty(&obj->sta2))
    {
     while(!StackEmpty(&obj->sta1))
    {
       StackPush(&obj->sta2,StackTop(&obj->sta1));
       StackPop(&obj->sta1);
    }  
    }
    //保存队头数据
    tmp=StackTop(&obj->sta2);
    //出队
     StackPop(&obj->sta2);
        return tmp;
}

int myQueuePeek(MyQueue* obj) {
    //sta2为空就倒数据
     if(StackEmpty(&obj->sta2))
     {
    while(!StackEmpty(&obj->sta1))
    {
       StackPush(&obj->sta2,StackTop(&obj->sta1));
       StackPop(&obj->sta1);
    }
     }
   //返回队头数据,不用出队
    int tmp=StackTop(&obj->sta2);
        return tmp;
}

//判断是否为空
bool myQueueEmpty(MyQueue* obj) {
    return StackEmpty(&obj->sta1)&&StackEmpty(&obj->sta2);
}

//销毁队列
void myQueueFree(MyQueue* obj) {
    StackDestroy(&obj->sta1);
    free(obj);
    obj=NULL;
}

以上就是分享的内容了,如有错误,评论区留言。

最后 ,谢谢大家的观看!

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

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

相关文章

杭电OJ 2044 一只小蜜蜂... C++

思路&#xff1a;本质与斐波那契数列一样&#xff0c;关键在于a与b之差 #include <iostream> #include <vector> using namespace std; int main() { vector<long long> nums(51); nums[0] 0; nums[1] 1; nums[2] 2; for (int i 3; i < 5…

设计模式——2_3 迭代器(Iterator)

生活就像一颗巧克力&#xff0c;你永远不知道下一颗是什么味道 ——《阿甘正传》 文章目录 定义图纸一个例子&#xff1a;假如你的采集器供应商提供了不同类型的返回值单独的遍历流程实现 碎碎念如果读写同时进行会发生啥&#xff1f;外部迭代和内部迭代迭代器和其他模式迭代器…

Spring框架知识点

Spring框架知识点 Spring框架中的单例Bean是线程安全的吗&#xff1f; 答&#xff1a;Spring框架中有一个Scope注解&#xff0c;默认值是singleton&#xff0c;单例的&#xff0c;当bean中定义了可变参数&#xff0c;就不是线程安全的。我们建议不要注入有状态的变量&#xf…

备战蓝桥杯Day21 - 堆排序的内置模块+topk问题

一、内置模块 在python中&#xff0c;堆排序已经设置好了内置模块&#xff0c;不想自己写的话可以使用内置模块&#xff0c;真的很方便&#xff0c;但是堆排序算法的底层逻辑最好还是要了解并掌握一下的。 使用heapq模块的heapify()函数将列表转换为堆&#xff0c;然后使用he…

librtmp源码分析

阅读了librtmp的源码&#xff0c;简单记录下。 首先补充下AMF格式基本知识 1 AMF格式 AMF是Action Message Format(动作消息格式)的简写&#xff0c;它是一种二进制的数据格式。它的设计是为了把actionscript里面的数据(包括Object, Array, Boolean, Number等)序列化成二进制…

工业现场网络性能评估方案

最近要去一个工厂排查网络和电脑卡顿的问题,为此&#xff0c;我准备了以下的方案&#xff0c;在现场以抓包和网络监控的方式来排查。 1.评估流程 为了评估Linux系统的网络负荷&#xff0c;并使用tcpdump来捕获数据包进行分析&#xff0c;您需要遵循以下几个步骤&#xff1a; …

一种基于三角剖分划分白区范围的白平衡算法

常规的白平衡算法中,一般会通过标准色温的R/G-B/G建议色温坐标系,然后在该坐标系中设定白区范围,对落入到白区范围的R/G/B进行加权统计处理,输出给到软件进行白平衡的增益计算。 所介绍的这篇专利利用三角剖分的算法,在划定的白区范围内,利用各个标准色温光源下所标定的白…

深入解析Golang的encoding/ascii85库:从基础到实战

深入解析Golang的encoding/ascii85库&#xff1a;从基础到实战 引言基础知识什么是ASCII85编码&#xff1f;ASCII85编码的工作原理ASCII85编码的优点ASCII85编码的缺点 使用Golang的encoding/ascii85库引入encoding/ascii85包ASCII85编码ASCII85解码实战示例小结 进阶技巧和最佳…

经典文献阅读之--CamMap(基于SLAM地图对不共视相机进行外参标定)

0. 简介 由于多相机之间通常存在有限或无重叠的视场&#xff0c;因此在估计外参相机参数时面临着一定的挑战&#xff0c;为了解决这个问题&#xff0c;本文提出了CamMap&#xff1a;一种新颖的6自由度外参标定流程。根据三个操作规则&#xff0c;使一个多相机系统单独捕捉一些…

垃圾回收APP:开启智能环保新篇章

随着科技的发展和人们生活水平的提高&#xff0c;智能手机已经成为我们生活中不可或缺的工具。而垃圾回收作为环保领域的重要组成部分&#xff0c;也正逐渐受到人们的关注和重视。为此&#xff0c;我们推出了一款创新的垃圾回收APP&#xff0c;旨在为环保事业注入科技力量&…

每日五道java面试题之mysql数据库篇(一)

目录&#xff1a; 第一题. 为什么要使用数据库?第二题. 数据库三大范式是什么?第三题. mysql有关权限的表都有哪几个?第四题. MySQL的binlog有有几种录入格式&#xff1f;分别有什么区别&#xff1f;第五题. MySQL存储引擎MyISAM与InnoDB区别 第一题. 为什么要使用数据库? …

SpringBoot实现短链跳转

目录 1.背景介绍 2.短链跳转的意义 3.SpringBoot中的代码实现 1.建议短链-长链的数据库表&#xff1a;t_url_map: 2.映射实体 3.Dao层实现 4.Service层实现 5.Controller层实现 3.结果测试 4.问题 1.背景介绍 短链跳转是一种通过将长链接转换为短链接的方式&…

Chrome浏览器新功能:节省内存,更方便查询内存占用情况

一、前言 Chrome浏览器一直被用户抱怨占用过多的内存&#xff0c;但是Google推出了Memory Saver功能来解决这个问题。该功能可以冻结不活跃的页面以节省内存。 现在&#xff0c;Google正在进一步开发这个功能&#xff0c;Chrome的Hover Cards功能将很快可以显示当前标签页使用了…

YOLOV8介绍

原文链接&#xff1a; 1、 详解YOLOv8网络结构/环境搭建/数据集获取/训练/推理/验证/导出 2、Yolov8的详解与实战 3、YOLOV8模型训练部署&#xff08;实战&#xff09;&#xff08;&#xff09;有具体部署和训练实现代码YOLOV8模型训练部署&#xff08;实战&#xff09;&…

bert 相似度任务训练,简单版本

目录 任务 代码 train.py predit.py 数据 任务 使用 bert-base-chinese 训练相似度任务&#xff0c;参考&#xff1a;微调BERT模型实现相似性判断 - 知乎 参考他上面代码&#xff0c;他使用的是 BertForNextSentencePrediction 模型&#xff0c;BertForNextSentencePred…

第三百七十六回

文章目录 1 .概念介绍2. 实现方法3. 示例代码 我们在上一章回中介绍了在页面之间共传递数据相关的内容&#xff0c;本章回中将介绍如何拦截路由.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1 .概念介绍 本章回中介绍的路由拦截是指在路由运行过程中&#xff0c;对路由做…

01tire算法

01tire算法 #include<bits/stdc.h> using namespace std; #define maxn 210000 int a[maxn], ch[maxn][2], val[maxn], n, ans, tot; void insert(int x) {int now 0;for (int j 31; j > 0; j -- ){int pos ((x >> i) & 1);if (!ch[now][pos])ch[now][po…

elasticsearch7.17 terms聚合性能提升90%+

背景 ES7 相比于 ES6 有多个层面的优化&#xff0c;对于开源的ES而言&#xff0c;升级是必经之路。 ES的使用场景非常多&#xff0c;在升级过程中可能会遇到非预期的结果&#xff1b; 比如之前文章提到的典型案例&#xff1a;ES7.17版本terms查询性能问题 ES7.17版本terms查…

服务端向客户端推送数据的实现方案

在日常的开发中&#xff0c;我们经常能碰见服务端需要主动推送给客户端数据的业务场景&#xff0c;比如数据大屏的实时数据&#xff0c;比如消息中心的未读消息&#xff0c;比如聊天功能等等。 本文主要介绍SSE的使用场景和如何使用SSE。 服务端向客户端推送数据的实现方案有哪…

maven项目导入mysql依赖

最近在B站跟着狂神学习Mybatis&#xff0c;学到P2就卡住了&#xff0c;搭建的maven项目一直无法导入依赖&#xff0c;在网上查找了很多相关的解决方法&#xff0c;project structure不知道点进去多少回&#xff0c;始终无法解决&#xff0c;后来把responsity文件夹删除重置了一…