通过“ 栈 ”实现“ 队列 ”

                           🌹个人主页🌹喜欢草莓熊的bear

                           🌹专栏🌹:数据结构


目录

前言

一、题目

1.1题目链接:用栈实现队列

1.2 题目描述

1.3 题目分析

二、模拟实现“ 队列 ” 的功能

2.1 结构体的定义

2.2 MyQueue* myQueueCreate() //初始化

2.3 void myQueuePush(MyQueue* obj, int x)//插入数据

2.4 int myQueuePop(MyQueue* obj)//返回元素并且删除

2.5 int myQueuePeek(MyQueue* obj)//返回开头元素

2.6 bool myQueueEmpty(MyQueue* obj)//判空

2.7 void myQueueFree(MyQueue* obj)//销毁

三、代码展示

总结


前言

在上期博客中我们通过在队列里面进行数据倒换来成功的实现了栈,那我们试试能不能通过在两个栈里面倒换数据来实现队列呢?

一、题目

1.1题目链接:用栈实现队列

1.2 题目描述

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

实现 MyQueue 类:

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

说明:

  • 你 只能 使用标准的栈操作 —— 也就是只有 push to toppeek/pop from topsize, 和 is empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

示例 1:

输入:
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]

解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false

提示:

  • 1 <= x <= 9
  • 最多调用 100 次 pushpoppeek 和 empty
  • 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)

1.3 题目分析

我们通过倒换两边栈的数据,就可以实现队列的特点" 先进先出  "。队列的其他功能在此基础上也比较好进行。

二、模拟实现“ 队列 ” 的功能

2.1 结构体的定义

根据之前的实现“ 栈 ”的经验我们可以重新定义一个结构体里面储存着两个栈就可以了,一个用来入数据一个用来出数据

typedef struct
{
    ST pushst;
    ST popst;
} MyQueue;

2.2 MyQueue* myQueueCreate() //初始化

我们动态申请一块空间,剩下的就是调用之前栈的初始化话说,和把size置为零。很简单和实现栈是一个道理。

MyQueue* myQueueCreate()
{
    MyQueue* q = (MyQueue*)malloc(sizeof(MyQueue));
    if (q == NULL)
    {
        perror("malloc");
    }
    STInit(&q->pushst);
    STInit(&q->popst);
    return q;
}

2.3 void myQueuePush(MyQueue* obj, int x)//插入数据

因为我们定义了两个栈,一个为入栈,一个为出栈。所以我们插入数据就只需插入到入数据的栈里面。

void myQueuePush(MyQueue* obj, int x)
{
    //只管往pushst里插入即可,不需要管
    STPush(&obj->pushst, x);
}

2.4 int myQueuePop(MyQueue* obj)//返回元素并且删除

我们这里分为两种情况,当出数据的栈为空时,和出数据的栈不为空。

出数据的栈为空时:那我们就要把入栈数据导入出数据的栈,然后进行删除。在删最后一个数据前把,最后一个数据储存后再删除返回刚刚储存的数据。

出数据的栈不为空:我们就直储存了数据,再进行释放数据。

int myQueuePop(MyQueue* obj)
{
    //需要讨论下,当pop这个栈为空时,需要将push栈中的数据导过来
    if (STEmpty(&obj->popst))
    {
        while (!STEmpty(&obj->pushst))//将push栈中的所有数据都导过去即可
        {
            STPush(&obj->popst, STTop(&obj->pushst));
            STPop(&obj->pushst);
        }
    }
    //走到这里有两种情况,可能push栈里的数据导光了,也可能是pop栈里本来就有数据,不为空
    int top = STTop(&obj->popst);
    STPop(&obj->popst);
    return top;
}

2.5 int myQueuePeek(MyQueue* obj)//返回开头元素

这边的返回开头元素和上一个删除并且返回元素十分相似,我们直接按照之前的思路写就可以了。

int myQueuePeek(MyQueue* obj)
{
    //这里跟pop数据很像,直接return 栈顶元素即可
     //需要讨论下,当pop这个栈为空时,需要将push栈中的数据导过来
    if (STEmpty(&obj->popst))
    {
        while (!STEmpty(&obj->pushst))//将push栈中的所有数据都导过去即可
        {
            STPush(&obj->popst, STTop(&obj->pushst));
            STPop(&obj->pushst);
        }
    }
    //走到这里有两种情况,可能push栈里的数据导光了,也可能是pop栈里本来就有数据,不为空
    return STTop(&obj->popst);

}

2.6 bool myQueueEmpty(MyQueue* obj)//判空

很简单直接调用我们之前写栈的判空

bool myQueueEmpty(MyQueue* obj)
{
    return STEmpty(&obj->pushst) && STEmpty(&obj->popst);
}

2.7 void myQueueFree(MyQueue* obj)//销毁

因为我们创建了两个栈,所以要先释放了两个栈的空间,再来释放把两个栈储存起来的结构体。

void myQueueFree(MyQueue* obj)
{
    STDestory(&obj->pushst);
    STDestory(&obj->popst);
    free(obj);
}

三、代码展示

#define _CRT_SECURE_NO_WARNINGS
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>//bool 类型的头文件
#include<assert.h>

typedef int STDataType;

typedef struct Stack
{
    STDataType* a;
    int top;//这里的top和顺序表的size相似的都是指有效元素的下一个数据。
    int capacity;
}ST;

void STInit(ST* pst)
{
    assert(pst);

    pst->a = NULL;
    pst->top = pst->capacity = 0;
}
void STDestory(ST* pst)
{
    assert(pst);

    free(pst->a);
    pst->a = NULL;
    pst->top = pst->capacity;
}

//入栈和出栈
void STPush(ST* pst, STDataType x)
{
    assert(pst);
    //扩容
    if (pst->top == pst->capacity)
    {
        int Newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
        STDataType* tmp = (STDataType*)realloc(pst->a, Newcapacity * sizeof(STDataType));
        if (tmp == NULL)
        {
            perror("ralloc fail");
            return;
        }
        pst->a = tmp;
        pst->capacity = Newcapacity;
    }
    pst->a[pst->top++] = x;
}
void STPop(ST* pst)
{
    assert(pst);
    assert(pst->top > 0);

    pst->top--;
}

//获取栈数据
STDataType STTop(ST* pst)
{
    assert(pst);
    assert(pst->top > 0);

    return pst->a[pst->top - 1];
}

//栈的判空
bool STEmpty(ST* pst)
{
    assert(pst);

    return pst->top == 0;
}
//栈的数据个数
int STSize(ST* pst)
{
    assert(pst);

    return pst->top;
}

typedef struct
{
    ST pushst;
    ST popst;
} MyQueue;


MyQueue* myQueueCreate()
{
    MyQueue* q = (MyQueue*)malloc(sizeof(MyQueue));
    if (q == NULL)
    {
        perror("malloc");
    }
    STInit(&q->pushst);
    STInit(&q->popst);
    return q;
}

void myQueuePush(MyQueue* obj, int x)
{
    //只管往pushst里插入即可,不需要管
    STPush(&obj->pushst, x);
}

int myQueuePop(MyQueue* obj)
{
    //需要讨论下,当pop这个栈为空时,需要将push栈中的数据导过来
    if (STEmpty(&obj->popst))
    {
        while (!STEmpty(&obj->pushst))//将push栈中的所有数据都导过去即可
        {
            STPush(&obj->popst, STTop(&obj->pushst));
            STPop(&obj->pushst);
        }
    }
    //走到这里有两种情况,可能push栈里的数据导光了,也可能是pop栈里本来就有数据,不为空
    int top = STTop(&obj->popst);
    STPop(&obj->popst);
    return top;
}

int myQueuePeek(MyQueue* obj)
{
    //这里跟pop数据很像,直接return 栈顶元素即可
     //需要讨论下,当pop这个栈为空时,需要将push栈中的数据导过来
    if (STEmpty(&obj->popst))
    {
        while (!STEmpty(&obj->pushst))//将push栈中的所有数据都导过去即可
        {
            STPush(&obj->popst, STTop(&obj->pushst));
            STPop(&obj->pushst);
        }
    }
    //走到这里有两种情况,可能push栈里的数据导光了,也可能是pop栈里本来就有数据,不为空
    return STTop(&obj->popst);

}

bool myQueueEmpty(MyQueue* obj)
{
    return STEmpty(&obj->pushst) && STEmpty(&obj->popst);
}

void myQueueFree(MyQueue* obj)
{
    STDestory(&obj->pushst);
    STDestory(&obj->popst);
    free(obj);
}

总结

我们完成栈和队列的互相实现,我们对栈和队列的理解就加深了一点。后面也会在带来一些关于队列和栈的题目,从而进一步加深。

  • 30
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值