千家信息网

C语言栈与队列怎么相互实现

发表于:2025-02-23 作者:千家信息网编辑
千家信息网最后更新 2025年02月23日,本篇内容介绍了"C语言栈与队列怎么相互实现"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、本章重点
千家信息网最后更新 2025年02月23日C语言栈与队列怎么相互实现

本篇内容介绍了"C语言栈与队列怎么相互实现"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

一、本章重点

  • 用两个队列实现栈

  • 用两个栈实现队列

  • 解题思路总结

二、队列实现栈

我们有两个队列:

入栈数据1、 2、 3

可以将数据入队列至队列一或者队列二。

如何出栈?

但出栈要先出1,怎么办?

第一步:

将队列一出队n-1个至队列二。

第二步:

pop队列一的最后一个元素。

接下来怎么入栈呢?

将元素入队至不为空的队列。

怎么判断栈空?

队列一和队列二都为空的情况下,栈就是空的。

如何取栈顶元素?

取不为空的队列尾部元素。

总的来说就是,入栈时就将数据插入不为空的队列,出栈就将不为空的队列的前n-1个数据导入至另一个队列,然后pop最后一个元素。

代码实现:

首先我们要构造一个栈。

这个栈要包含两个队列

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

在此之前我们要准备好队列的一般接口:

我这里的队列是用单链表来构建的,具体接口实现可以看我之前的文章。

typedef int QTypeData;typedef struct QueueNode{        struct QueueNode* next;        QTypeData val;}QN; void QueueInit(Queue* pq)//初始化队列size_t QueueSize(Queue* pq)//求队列元素个数int QueueBack(Queue* pq)//取队列尾部数据void QueuePush(Queue* pq, QTypeData x)//将x入队void QueuePop(Queue* pq)//出队void QueueDestroy(Queue* pq)//结束队列

我们要用队列实现栈的接口:

  • 第一个接口:创建并初始化栈

接口一:MyStack* myStackCreate()

这样做行吗?

MyStack* myStackCreate(){     MyStack ms;    QueueInit(&ms.q1);    QueueInit(&ms.q2);    return ms;}

很显然,返回局部变量的地址是不明智的,因为在函数返回时,ms开辟的空间会重新交给操作系统,再次访问就是非法操作。

因此我们需要将ms开辟在堆区。

参考代码:

  • 第二个接口:入栈

接口二:void myStackPush(MyStack* obj, int x)

入栈简单:只要将数据插入到不为空的队列即可。

入栈之前我们需要判断队列满吗?

不需要,因为我的队列是用单链表实现的,可以无限链接下去。

如果两个队列都为空,该插入到哪个队列呢?

我们可以这样做,如果队列1为空,就插入到队列2,如果不为空,就插入到队列1.

参考代码:

  • 第三个接口:出栈

接口三:int myStackPop(MyStack* obj) //出栈

再次回顾一下我们是如何出栈的。

首先我们有两个队列

初始状态它们都是空的

队列一:空

队列二:空

入栈1、2、3、4

执行后

队列一:空

队列二:1、2、3、4

出队列只能先出1,如何出4呢?

把1、2、3先出给队列一

执行后

队列一:1、2、3

队列二:4

然后将4用变量记录并出队,最后返回记录4的变量。

执行后

队列一:1、2、3

队列二:空。

出队三板斧

第一步:即将不为空的队列的前n-1个元素入至为空的队列。

第二步:将剩下的1个元素用变量记录,然后将最后一个元素出队。

第三步:返回用变量记录的元素。

需要注意的是:如果栈为空,那么就返回false。

参考代码:

  • 第四个接口:取栈顶元素

接口四:int myStackTop(MyStack* obj) //取栈顶元素

取栈顶元素之前我们需要保证栈不为空

如果栈为空,返回false。

取栈顶元素,即取不为空的队列的队尾元素。

参考代码:

  • 第五个接口:判断栈是否为空

接口五:bool myStackEmpty(MyStack* obj) //判断栈是否为空

如果两个队列都是空的那么该栈就是空的。

这里多提一下,栈的元素个数怎么求?

栈的元素个数就是那个不为空队列的元素个数。

参考代码:

  • 第六个接口:销毁栈

接口六:void myStackFree(MyStack* obj) //结束栈

参考代码:

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

最后需要注意的是:调用栈为空的接口时,要先声明!!

三、栈实现队列

第一次入队

将数据1出队操作

将栈1的数据全导入栈2

然后栈2进行出栈操作

再次入队5、6、7

直接将5、6、7入栈至栈1

实际我们的对头和队尾是这样的

总的来说:

用两个栈实现一个队列,就得把一个栈专门入队,另一个栈用作出队。这里实现的时候我们用栈1做入队栈,栈2做出队栈。

也就是说,只要将数据入队,直接放入栈1.

出队就直接出栈2的数据,如果栈2为空,这将栈1的数据全部导入栈2.

队列的结构体:

typedef struct {    ST st1;    ST st2;} MyQueue;

我们需要准备的栈

typedef int STDataType;typedef struct Stack{        STDataType* data;        int top;        int capacity;}ST;

这里我用的是动态数组实现的栈

需要提前准备栈的接口:

void STInit(ST* p)void STDestroy(ST* p)void STPush(ST* p,STDataType x)void STPop(ST* p)bool STEmpty(ST* p)int STSize(ST* p)STDataType STRear(ST* p)
  • 第一个接口:创建并初始化队列

MyQueue* myQueueCreate()

同样的,需要把队列开辟在堆区,同时对栈1和栈2进行初始化。

参考代码:

MyQueue* myQueueCreate() {    MyQueue* mq=(MyQueue*)malloc(sizeof(MyQueue));    assert(mq);    STInit(&mq->st1);    STInit(&mq->st2);    return mq;}
  • 第二个接口:入队

void myQueuePush(MyQueue* obj, int x)

我们把栈1做入队栈,栈2做出队栈。

也就是说,只要将数据入队,直接放入栈1.

出队就直接出栈2的数据,如果栈2为空,这将栈1的数据全部导入栈2.

参考代码:

void myQueuePush(MyQueue* obj, int x) {    STPush(&obj->st1,x);}
  • 第三个接口:出队

int myQueuePop(MyQueue* obj)

先要判断队列是否为空,如果队列为空则返回false。

其次如果栈2为空,就将栈1的数据全导入栈2.

参考代码:

int myQueuePop(MyQueue* obj) {    if(myQueueEmpty(obj))    {        return false;    }    if(STEmpty(&obj->st2))    {        int n=STSize(&obj->st1);        while(n--)        {            STPush(&obj->st2,STRear(&obj->st1));            STPop(&obj->st1);        }    }    int ret=STRear(&obj->st2);    STPop(&obj->st2);    return ret;}

第四个接口:取队头元素

int myQueuePeek(MyQueue* obj)

取队头元素之前,要判断队列是否为空,如果为空,则返回false

队头元素即栈2的尾部元素。

但如果栈2为空呢?

那队列的队头元素就是栈1的头部元素。

参考代码:

int myQueuePeek(MyQueue* obj) {    if(myQueueEmpty(obj))    {        return false;    }    if(STEmpty(&obj->st2))    {        return STFront(&obj->st1);    }    return STRear(&obj->st2);}

第五个接口:判断队列是否为空

bool myQueueEmpty(MyQueue* obj)

队列为空,需要栈1和栈2都为空。

参考代码:

bool myQueueEmpty(MyQueue* obj) {    return STEmpty(&obj->st1) && STEmpty(&obj->st2);}

第六个接口:销毁队列

void myQueueFree(MyQueue* obj)

参考代码:

void myQueueFree(MyQueue* obj) {    STDestroy(&obj->st1);    STDestroy(&obj->st2);    free(obj);}

注意:当使用判断队列是否为空的接口时,注意是否在之前声明过了。

四、解题思路总结

1.用队列实现栈:

我们需要用两个队列实现栈

栈类是于尾插尾删

队列是尾插头删

第一次入栈:两个队列都为空,随便插入一个队列都可

第一次出栈:出栈要出的是尾部数据,队列只能出头部数据,这是队列不能直接实现的。

那么需要将不为空的队列前n-1个数据导入至为空的队列,再将最后一个元素pop掉。

队列一:1、2、3、4

队列二:空

那么导入后

队列一:4

队列二:1、2、3

最后pop最后一个元素

队列一:空

队列二:1、2、3、4

再次尾插:尾插至不为空的队列即可。

2.用栈实现队列

我们有两个栈要求实现队列的一般接口

栈一:空

栈二:空

第一次入队:入栈至栈一或者栈二都可,这里选择栈一。

假设入队1、2、3、4

栈一:1、2、3、4

栈二:空

出队:要先出1

将栈一全部导入栈二

栈一:空

栈二:4、3、2、1

之后入队就插入至栈一

出队就pop栈二。

"C语言栈与队列怎么相互实现"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

队列 元素 接口 数据 代码 参考 两个 就是 变量 个数 再次 尾部 第一次 先出 准备 语言 接下来 三个 也就是 也就是说 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 网络技术研究方向 护苗 网络安全课手抄报 四川工控软件开发价格 服务器被ddos报警有用吗 浦东新区及时网络技术铸造辉煌 计算机二三级网络技术及应用 查看服务器文件系统 2008服务器系统下载官网 软件开发及维护的理念 网络技术用英语怎么说读 有关互联网科技的问题 vc与数据库开发技术的特点 虚拟网络安全专业就业前景 巨杉数据库多租户能力 服务器硬盘是什么格式的 昆明服务器上门回收价格 库存 缓存和数据库更新 棋牌软件开发有哪些公司呢 安徽慧暖软件开发有限公司 百度实时路况来源于网络技术 sql数据库查看连接用户 哈尔滨 软件开发 黑ICP 易语言数据库制作教程下载 伟创网络技术公司招聘 linux服务器远程连接 ssr服务器节点超时 天猫精灵老是显示服务器出错 百通赫思曼网络技术 win10服务器链接怎么打开 猎鹰网络安全代理
0