栈和队列的转化

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

栈与队列的相互转换

栈和队列是两种基本的数据结构,它们在许多算法和程序中都有应用。
虽然栈和队列在概念上是完全不同的,但是我们可以使用两个栈来实现一个队列,或者使用两个队列来实现一个栈。这种转换在某些情况下可能非常有用,例如,当我们的编程环境只提供了栈或队列的实现,但我们需要使用另一种数据结构时。
在这篇博客中,我们将详细介绍如何使用两个栈来实现一个队列,以及如何使用两个队列来实现一个栈。我们将提供详细的代码示例,并解释每个函数的工作原理。


提示:以下是本篇文章正文内容,下面案例可供参考

一、栈和队列的基本操作

在深入了解如何使用栈实现队列或使用队列实现栈之前,我们首先需要理解栈和队列的基本操作。

栈的基本操作

「栈 stack」是一种遵循先入后出的逻辑的线性数据结构,只允许在一端(称为栈顶)进行插入和删除操作。以下是栈的基本操作:

  1. Push:将一个元素添加到栈顶。
  2. Pop:从栈顶移除一个元素。
  3. Peek:访问栈顶元素。
  4. IsStackEmpty:检查栈是否为空。
  5. ClearStack:清空栈。
    在这里插入图片描述

队列的基本操作

「队列 queue」是一种遵循先入先出规则的线性数据结构,允许在一端(称为队尾)进行插入操作,在另一端(称为队头)进行删除操作。以下是队列的基本操作:

  1. Enqueue:将一个元素添加到队尾。
  2. Dequeue:从队头移除一个元素。
  3. Front:获取队头元素
  4. IsQueueEmpty:检查队列是否为空。
  5. ClearQueue:清空队列。

在这里插入图片描述
理解这些基本操作是实现更复杂的数据结构的关键。在接下来的部分中,我们将看到如何使用这些基本操作来实现我们的目标。

二、两个栈实现一个队列

1.思路阐述

基本的想法是使用一个栈s1来接收新元素(入队操作),另一个栈s2用于执行出队操作。这样,通过两个栈之间的来回转化,我们就可以保证元素的顺序满足队列的先进先出(FIFO)特性。
数据结构定义
首先,我们定义一个名为MyQueue的结构,它包含两个栈s1s2

typedef struct MyQueue
{
    Stack *s1;
    Stack *s2;
}MQueue;

2.接口实现

初始化

我们需要一个函数来初始化这个队列,即初始化两个栈:

void InitMQueue(MQueue *q)
{
    InitStack(q->s1);
    InitStack(q->s2);
}

入队

入队时:若s2为空则直接将数据入栈s1;若s2不为空则先将s2所有元素入栈至s1,再将新元素入栈s1.

void MyEnqueue(MQueue *q,int element)
{
    while(IsStackEmpty(q->s2) == false)	//如果s2不为空
    {
        Push(q->s1,*Front(q->s2));   	//就先把s2的元素,倒回到s1
        Pop(q->s2);                    	//再将s2所有元素出栈
    }
    Push(q->s1,element);               //如果s2为空,就直接入栈s1
}

判空

我们需要一个函数来检查队列是否为空,即检查s1s2是不是空

//队列是否为空
bool IsMQueueEmpty(MQueue *q)
{
    return IsStackEmpty(q->s1) && IsStackEmpty(q->s2);
}

出队

出队时:先判断s1s2为不为空;若不为空,就先将s1元素所有入栈至s2,在将s2元素出栈即可。

void MyDequeue(MQueue *q)
{
	//判断队列是否为空
    if(IsMQueueEmpty(q) == true)
    {
        printf("队列为空!\n");
        return ;
    }
    //不管什么情况,先把s1的元素,倒到s2
    while(IsStackEmpty(q->s1) == false) 
    {
        Push(q->s2,*Front(q->s2));
        Pop(q->s1);
    }
    Dequeue(q->s2);
}

获取队头元素

我们还需要一个函数来获取队头元素,但不移除它:

int *MyFront(MQueue *q)
{
    //判断队列是否为空
    if(IsMQueueEmpty(q) == true)
    {
        printf("队列为空!\n");
        return ;
    }
    //不管什么情况,先把s1的元素,倒到s2
    while(IsStackEmpty(q->s1) == false) 
    {
        Push(q->s2,*Front(q->s2));
        Pop(q->s1);
    }
    return Peek(q->s2);
}

清空队列

最后,我们需要一个函数来清空队列,即清空两个栈:

void ClearMQueue(MQueue *q)
{
    ClearStack(q->s1);
    ClearStack(q->s2);
}

二、两个队列实现一个栈

1.思路阐述

基本的想法是使用两个栈进行元素的存储,当需要入队时;就将元素正常入队,当需要出队列时,就将两个栈的数据变成多加一,返回只有一个数据的那个栈里的数据。

数据结构定义
首先,我们定义一个名为MyStack的结构,它包含两个队列q1q2,以及一个元素data用于存储栈顶元素:

typedef struct MyStack
{
    Queue *q1;
    Queue *q2;
    int data;//存储栈顶元素
}MStack;

入栈时:

2.接口实现

初始化

我们需要一个函数来初始化这个栈,即初始化两个队列:

void InitMStack(MStack *s)
{
    InitQueue(s->q1);
    InitQueue(s->q2);
}

入栈

入栈操作是将一个元素添加到有元素的那个队列中去,保证两个队列一个有元素一个为空。

//入栈:保证一个队列是空的,并且入栈到有元素的那一个队列
void MySPush(MStack *s,int element)
{
    if(IsQueueEmpty(s->q1) == true)
    {
        Enqueue(s->q2,element);
    }
    else
    {
        Enqueue(s->q1,element);
    }
}

判空

我们需要一个函数来检查栈是否为空,即检查p1p2是不是空

bool IsMStackEmpty(MStack *s)
{
    return IsQueueEmpty(s->q1) && IsQueueEmpty(s->q2);
}

出栈和获取栈顶元素

出栈操作是将有元素的那个队列,入队到空的那个队列中去,只留一个元素,然后将这一个元素出队。

ElementType *MySPop(MStack *s)
{
    if(IsMStackEmpty(s) == true)    //判断栈是否为空
    {
        printf("栈为空!\n");
        return NULL;
    }
    else if(IsQueueEmpty(s->q1) == true)//如果q1为空
    {
        //将q2中的元素,放到q1中去,只剩一个栈顶元素
        while(GetQueueLen(s->q2) > 1)
        {
            Enqueue(s->q1,*Front(s->q2));
            Dequeue(s->q2);
        }
        //把即将被销毁的栈顶元素的数据另存,并把原来指向它的指针改向,
        //指向另存的数据地址
        s->data = *Front(s->q2);
        //弹出栈顶元素
        Dequeue(s->q2);
    }
    else
    {
        while(GetQueueLen(s->q1) > 1)
        {
            Enqueue(s->q2,*Front(s->q1));
            Dequeue(s->q1);
        }
        s->data = *Front(s->q1);
        Dequeue(s->q1);
    }
    return &s->data;
}

清空栈

最后,我们需要一个函数来清空栈,即清空两个队列:

void ClearMStack(MStack *s)
{
    ClearQueue(s->q1);
    ClearQueue(s->q2);
}

总结

在这篇博客中,我们详细介绍了如何使用两个栈来实现一个队列,以及如何使用两个队列来实现一个栈。我们提供了详细的代码示例,并解释了每个函数的工作原理。

通过使用两个栈实现队列,我们可以看到数据结构之间的相互转换是如何可能的。同样,通过使用两个队列实现栈,我们也可以看到这种转换的另一面。

这种转换在某些情况下可能非常有用,例如,当我们的编程环境只提供了栈或队列的实现,但我们需要使用另一种数据结构时。

希望这篇博客能帮助你更好地理解栈和队列,以及它们如何相互转换。如果你有任何问题或想法,欢迎在评论区留言。谢谢你的阅读,期待你的下次访问!

  • 25
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值