【栈和队列经典题目】用队列实现栈,用栈实现队列,设计循环队列

一.用队列实现栈

在这里插入图片描述

栈的特点就是后进先出,满足这一要求的结构就能被称作栈,至于怎么实现的就是另一回事,反正我将函数接口给你,你只管用就行。一般情况下,我们使用顺序结构来实现栈,原因是栈只需要对一端进行操作,例如入栈,出栈,取栈顶元素等都是在栈顶进行操作。而顺序结构对尾部的插入删除效率还是蛮高的,故我们可将数组的头部当作栈底,尾部当作栈顶,这种实现方式应当是最简单高效的了。

  1. 入栈:将数据插入不为空的哪一个队列中,若两个队列均为空,插入任意一个都行
  2. 出栈:将非空队列的数据导入到另一个队列中,直到只剩下一个元素,该元素即为要出栈的元素,pop掉即可
  3. 判栈空:若两个队列均为空,则栈空
  4. 返回栈顶元素:取非空队列的队尾元素即可

代码如下(省略了队列的实现)

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


MyStack* myStackCreate() {
    MyStack* obj = malloc(sizeof(MyStack));
    QueueInit(&obj->q1);
    QueueInit(&obj->q2);
    return obj;
}

bool myStackEmpty(MyStack* obj) {
    return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}

void myStackPush(MyStack* obj, int x) {
    assert(obj);
    //非空队列push
    //都为空随便哪个都行
    Queue* pNonEmptyQ = &obj->q1;
    Queue* pEmptyQ = &obj->q2;
    if (QueueEmpty(&obj->q1))
    {
        pEmptyQ = &obj->q1;
        pNonEmptyQ = &obj->q2;
    }
    QueuePush(pNonEmptyQ, x);
}

int myStackPop(MyStack* obj) {
    assert(obj);
    assert(!myStackEmpty(obj));
    
    Queue* pNonEmptyQ = &obj->q1;
    Queue* pEmptyQ = &obj->q2;
    if (QueueEmpty(&obj->q1))
    {
        pEmptyQ = &obj->q1;
        pNonEmptyQ = &obj->q2;
    }
    //导数据到空队列直到只剩一个元素
    while (QueueSize(pNonEmptyQ) > 1)
    {
        int front = QueueFront(pNonEmptyQ);
        QueuePush(pEmptyQ, front);
        QueuePop(pNonEmptyQ);
    }
    
    int top = QueueFront(pNonEmptyQ);
    QueuePop(pNonEmptyQ);
    return top;
}

int myStackTop(MyStack* obj) {
    assert(obj);
    assert(!myStackEmpty(obj));
    if (!QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }
    else
    {
        return QueueBack(&obj->q2);
    }
}



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

二.用栈实现队列

在这里插入图片描述
队列的特点是先进先出,常规的队列是用链式结构来实现的。因为队列要对两端进行操作(入队和出队),而顺序表对尾部插入删除效率很高,但是对头部操作时要大量地移动数据,非常麻烦。所以采用链表来实现队列比较合理,链表的头插和尾插效率都很高,同时为了避免频繁地找尾,于是设置一个尾指针rear。

设置两个栈,一个用于push,另一个用于pop
入队:将数据插入用于push的栈
出队:将数据从用于pop的栈中弹出来,若pop栈为空,就将push栈中的数据导入进来再操作
判队空:若两个栈都为空,则队已空。
取队头:操作和出队类似

代码如下(省略栈的实现)

MyQueue* myQueueCreate() {
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    STInit(&obj->pushst);
    STInit(&obj->popst);
    return obj;
}

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

void myQueuePush(MyQueue* obj, int x) {
    assert(obj);
    STPush(&obj->pushst, x);
}

int myQueuePeek(MyQueue* obj) {
    assert(!myQueueEmpty(obj));
    if (STEmpty(&obj->popst))
    {
        //将pushst数据全部导到popst
        while (!STEmpty(&obj->pushst))
        {
            int top = STTop(&obj->pushst);
            STPop(&obj->pushst);
            STPush(&obj->popst, top);
        }
    }
    int top = STTop(&obj->popst);
    return top;
}

int myQueuePop(MyQueue* obj) {
    int top = myQueuePeek(obj);
    STPop(&obj->popst);
    return top;
}

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

三.设计循环队列

在这里插入图片描述
本题采用数组来实现循环队列。
在这里插入图片描述
如上图所示,假如这个循环队列最多只能存5个数据,我就开辟一个空间为6的数组,其中一个不存放数据。为什么要这样做呢?是为了区分队空与队满的情况。

代码实现:

typedef struct {
    int* a;
    int k;//最多元素个数
    int front;
    int rear;
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->a = (int*)malloc(sizeof(int)*(k + 1));
    obj->front = obj->rear = 0;
    obj->k = k;
    return obj;
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    assert(obj);
    return obj->front == obj->rear;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    assert(obj);
    return (obj->rear + 1) % (obj->k + 1) == obj->front;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    assert(obj);
    if (myCircularQueueIsFull(obj))
    {
        return false;
    }
    obj->a[obj->rear] = value;
    obj->rear = (obj->rear + 1) % (obj->k + 1);
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    assert(obj);
    if (myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    obj->front = (obj->front + 1) % (obj->k + 1);
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) {
    assert(obj);
    if (myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->a[obj->front];
}

int myCircularQueueRear(MyCircularQueue* obj) {
    assert(obj);
    if (myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->a[(obj->rear + obj->k) % (obj->k + 1)];
}



void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->a);
    free(obj);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值