• 【C语言刷题】用队列实现栈和用栈实现队列


    活动地址:CSDN21天学习挑战赛


    Leetcode225——用队列实现栈

    题目描述

    请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
    实现 MyStack 类:

    • void push(int x) 将元素 x 压入栈顶。
    • int pop() 移除并返回栈顶元素。
    • int top() 返回栈顶元素。
    • boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。


    链接https://leetcode.cn/problems/implement-stack-using-queues

    注意
    你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
    你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

    示例

    输入:[“MyStack”, “push”, “push”, “top”, “pop”, “empty”]
    [[ ], [1], [2], [ ], [ ], [ ]]
    输出:[null, null, null, 2, 2, false]
    解释:MyStack myStack = new MyStack();
    myStack.push(1);
    myStack.push(2);
    myStack.top(); // 返回 2
    myStack.pop(); // 返回 2
    myStack.empty(); // 返回 False


    提示

    • 1 <= x <= 9
    • 最多调用100 次 push、pop、top 和 empty
    • 每次调用 pop 和 top 都保证栈不为空

    核心代码模式

    typedef struct 
    {
    
    } MyStack;
    
    
    MyStack* myStackCreate() 
    {
    
    }
    
    void myStackPush(MyStack* obj, int x) 
    {
    
    }
    
    int myStackPop(MyStack* obj) 
    {
    
    }
    
    int myStackTop(MyStack* obj) 
    {
    
    }
    
    bool myStackEmpty(MyStack* obj) 
    {
    
    }
    
    void myStackFree(MyStack* obj) 
    {
    
    }
    
    /**
     * Your MyStack struct will be instantiated and called as such:
     * MyStack* obj = myStackCreate();
     * myStackPush(obj, x);
     
     * int param_2 = myStackPop(obj);
     
     * int param_3 = myStackTop(obj);
     
     * bool param_4 = myStackEmpty(obj);
     
     * myStackFree(obj);
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    思路分析与代码实现(C语言)

    要用两个队列实现栈,题目没有提供队列,而C语言库中没有数据结构,所以我们得先手搓队列结构和操作函数。

    typedef int QDataType;
    typedef struct QueueNode
    {
        struct QueueNode* next;
        QDataType data;
    }QNode;
    
    typedef struct Queue
    {
        QNode* front;
        QNode* rear;
        size_t size;
    }Que;
    
    void QueueInit(Que* pQ);
    void QueueDestory(Que* pQ);
    void QueuePush(Que* pQ, QDataType tar);
    void QueuePop(Que* pQ);
    QDataType QueueFront(Que* pQ);
    QDataType QueueRear(Que* pQ);
    bool QueueEmpty(Que* pQ);
    int QueueSize(Que* pQ);
    
    void QueueInit(Que* pQ)
    {
    	assert(pQ);
    
    	pQ->front = pQ->rear = NULL;
    	pQ->size = 0;
    }
    
    void QueuePush(Que* pQ, QDataType tar)
    {
    	assert(pQ);
    
    	QNode* newNode = (QNode*)malloc(sizeof(QNode));
    	if (newNode == NULL)
    	{
    		perror("malloc fail");
    		exit(-1);
    	}
    	else
    	{  //不为空就初始化结点
    		newNode->data = tar;
    		newNode->next = NULL;
    	}
    
    	if (pQ->rear == NULL)
    	{
    		pQ->front = pQ->rear = newNode;
    	}
    	else
    	{
    		pQ->rear->next = newNode;
    		pQ->rear = newNode;
    	}
    	pQ->size++;
    }
    
    bool QueueEmpty(Que* pQ)
    {
    	assert(pQ);
    
    	return pQ->front == NULL && pQ->rear == NULL;
    }
    
    void QueuePop(Que* pQ)
    {
    	assert(pQ);
    	assert(!QueueEmpty(pQ));
    
    	if (pQ->front->next == NULL)
    	{
    		free(pQ->front);
    		pQ->front = pQ->rear = NULL;
    	}
    	else
    	{
    		QNode* del = pQ->front;
    		pQ->front = pQ->front->next;
    		free(del);
    	}
    	pQ->size--;
    }
    
    QDataType QueueFront(Que* pQ)
    {
    	assert(pQ);
    	assert(!QueueEmpty(pQ));
    	
    	return pQ->front->data;
    }
    
    QDataType QueueRear(Que* pQ)
    {
    	assert(pQ);
    	assert(!QueueEmpty(pQ));
    
    	return pQ->rear->data;
    }
    
    int QueueSize(Que* pQ)
    {
    	assert(pQ);
    
    	return pQ->size;
    }
    
    void QueueDestory(Que* pQ)
    {
    	assert(pQ);
    
    	QNode* cur = pQ->front;
    	while (cur)
    	{
    		QNode* del = cur;
    		cur = cur->next;
    		free(del);
    	}
    	pQ->front = pQ->rear = NULL;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121

    栈结构声明
    既然是要用两个队列实现栈,那不妨把两个队列放到栈结构体中。下面那个是创建栈的函数,直接用malloc在堆区创建,初始化栈结构,返回指针即可。

    typedef struct 
    {
        Que q1;
        Que q2;
    } MyStack;
    
    
    MyStack* myStackCreate() 
    {
        MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
        QueueInit(&obj->q1);
        QueueInit(&obj->q2);
        return obj;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    如何实现元素入栈呢?
    如果是第一次放入元素,那两个队列都是空的,这时候把元素放哪个队列都行。如果已经有放入过元素了,那就看哪个队列不是空的就放入哪个队列中去,为什么这样做呢?是为了配合元素出栈的实现方式,后面讲的时候你就能明白了。直接复用我们前面实现了的队列操作函数来操作队列即可。

    void myStackPush(MyStack* obj, int x) 
    {
        if(!QueueEmpty(&obj->q1))
        {
            QueuePush(&obj->q1, x);
        }
        else
        {
            QueuePush(&obj->q2, x);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    如何实现元素出栈呢?
    先把装了元素的队列的队尾之前的所有元素移动到另一个队列,再让之前的队尾元素出队列。由于队列先进先出的特性,将元素从一个队列导入到另一队列中去,元素间相对顺序不变。我们要用队列实现栈,也就是将先进先出的特性转换为后进先出的特性,队列后进入的元素(比如下图的4)在队列中自然不能直接出队列,队尾可不能出元素,而队头的话还得把1、2、3先出完才能轮到4,于是乎我们这里的方法就是让后进入的元素直接一跃到队头,那前面不是有好几个的元素嘛,不可能会说没就没的呀,不是还有一个队列嘛,那我们就先把不出去的元素全部放到另一个队列去呗。
    先进先出是因为先进入的直接到了队头,那要实现后进先出,可以让先进入的“靠边站”,把队头位置让给后进入的,这样后进入的也可以先出。
    所以每次要出栈的时候,就把前面元素先导入到另一个队列中去,然后再把剩下那个元素出队列即可,所以会始终保持一个队列为空。
    image.png
    我们不区分q1和q2,只区分区分空和非空。由于题目保证了每次调用 pop 和 top 都保证栈不为空,所以我们这里不考虑栈为空的情况。要注意这个函数有返回值,返回的是pop出来的值。

    int myStackPop(MyStack* obj) 
    {
        Que* empty = &obj->q1;
        Que* nonEmpty = &obj->q2;
        if(!QueueEmpty(&obj->q1))
        {
            empty = &obj->q2;
            nonEmpty = &obj->q1;
        }
        
        while(nonEmpty->size > 1)
        {
            QueuePush(empty, QueueFront(nonEmpty));
            QueuePop(nonEmpty);
        }
        
        int ret = QueueFront(nonEmpty);
        QueuePop(nonEmpty);
        return ret;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    判断栈是否为空
    由于这个栈是由两个队列组合而成的,所以判断栈是否为空,只需判断两个队列是否都为空即可。

    bool myStackEmpty(MyStack* obj)
    {
        
        return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    获取栈顶元素
    鉴于我们这种思路,两个队列总会保持一种状态:一个队列为空,另一个不为空。这时候,不为空的队列的队尾元素就是栈的栈顶元素。

    int myStackTop(MyStack* obj) 
    {
        if(!QueueEmpty(&obj->q1))
            return QueueRear(&obj->q1);
        else
            return QueueRear(&obj->q2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    释放栈结构
    你肯定记得释放栈,但是你记不记得我们这儿的队列使用单链表实现的?要先释放掉两个队列的单链表,再释放掉整个栈结构。

    void myStackFree(MyStack* obj) 
    {
        QueueDestory(&obj->q1);
        QueueDestory(&obj->q2);
        free(obj);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Leetcode232——用栈实现队列

    题目描述

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

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

    链接https://leetcode.cn/problems/implement-queue-using-stacks

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

    **示例 **:

    输入
    [“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 次 push、pop、peek 和 empty
    • 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)

    核心代码模式

    typedef struct {
    
    } MyQueue;
    
    
    MyQueue* myQueueCreate() {
    
    }
    
    void myQueuePush(MyQueue* obj, int x) {
    
    }
    
    int myQueuePop(MyQueue* obj) {
    
    }
    
    int myQueuePeek(MyQueue* obj) {
    
    }
    
    bool myQueueEmpty(MyQueue* obj) {
    
    }
    
    void myQueueFree(MyQueue* obj) {
    
    }
    
    /**
     * Your MyQueue struct will be instantiated and called as such:
     * MyQueue* obj = myQueueCreate();
     * myQueuePush(obj, x);
     
     * int param_2 = myQueuePop(obj);
     
     * int param_3 = myQueuePeek(obj);
     
     * bool param_4 = myQueueEmpty(obj);
     
     * myQueueFree(obj);
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    思路分析与代码实现(C语言)

    由于C语言库里没有数据结构,我们这里得先手搓栈的结构和操作函数。

    typedef int STDataType;
    typedef struct stack
    {
        STDataType* arr;
        int top;
        size_t capacity;
    }ST;
    
    
    void StackInit(ST* pS);
    void StackDestory(ST* pS);
    void StackPush(ST* pS, STDataType tar);
    bool StackEmpty(ST* pS);
    void StackPop(ST* pS);
    STDataType StackTop(ST* pS);
    int StackSize(ST* pS);
    
    void StackInit(ST* pS)
    {
        assert(pS);
    
        pS->arr = NULL;
        pS->top = pS->capacity = 0;
    }
    
    void StackPush(ST* pS, STDataType tar)
    {
        assert(pS);
    
        //检查是否满容以及扩容
        if (pS->top == pS->capacity)
        {
            int newCapacity = (pS->capacity == 0) ? 4 : pS->capacity * 2;
            ST* tmp = (STDataType*)realloc(pS->arr, newCapacity * sizeof(STDataType));
            if (tmp == NULL)
            {
                perror("realloc fail");
                exit(-1);
            }
            pS->capacity = newCapacity;
            pS->arr = tmp;
        }
        //元素入栈
        pS->arr[pS->top] = tar;
        pS->top++;
    }
    
    void StackDestory(ST* pS)
    {
        assert(pS);
    
        free(pS->arr);
        pS->arr = NULL;
        pS->top = pS->capacity = 0;
    }
    
    bool StackEmpty(ST* pS)
    {
        assert(pS);
    
        return pS->top == 0;
    }
    
    void StackPop(ST* pS)
    {
        assert(pS);
        assert(!StackEmpty(pS));
    
        --pS->top;
    }
    
    STDataType StackTop(ST* pS)
    {
        assert(pS);
        assert(!StackEmpty(pS));
    
        return pS->arr[pS->top - 1];
    }
    
    int StackSize(ST* pS)
    {
        assert(pS);
    
        return pS->top;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    那么如何用两个栈来实现队列呢?我们一点一点来看吧。
    比如说在st1已经入栈了四个元素,这时候要出队列,根据先进先出,就是要把1出栈,可以1在st1最下面啊,怎么搞呢?让它变成栈顶元素就能出栈了吧,那可不可以把这四个元素依次导入到st2中,这样的话1就变成了st2的栈顶元素,这时候就可以出栈了。
    image.png
    那还需要再把2、3、4再导回到st1中去吗?其实不需要了,你看啊,出队列是不是就在st2实现了,而入队列是不是就在st1实现了,那可不可以假象着把它们两个栈拼接在一起,组成一个模拟队列呢?
    image.png
    栈pushST用来入元素,栈popST用来出元素,等到出空了,再去pushST把数据导入进来。

    队列结构声明与队列创建

    由于是要用两个栈实现,我们就放入两个栈结构,一个pushST,一个popST。创建好队列后,复用栈的初始化函数,初始化两个栈。

    typedef struct {
        ST pushST;
        ST popST;
    } MyQueue;
    
    
    MyQueue* myQueueCreate() {
        MyQueue* obj =(MyQueue*)malloc(sizeof(MyQueue));
        StackInit(&obj->pushST);
        StackInit(&obj->popST);
        return obj;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    元素入队列

    结合前面所讲的,pushST栈就是用来入元素的,也没有什么限制,直接复用入栈操作函数即可。

    void myQueuePush(MyQueue* obj, int x) {
        StackPush(&obj->pushST);
    }
    
    • 1
    • 2
    • 3

    元素出队列

    出队列前要先看看popST是不是空的,如果不是空,就可以直接把popST的元素出栈,如果是空的,那就要先把pushST的元素全部导入popST中再出栈。我们不妨把导入元素的操作封装成一个函数PushSTtoPopST( )。

    void PushSTtoPopST(MyQueue* obj)
    {
        if(StackEmpty(&obj->popST))
        {
            while(!StackEmpty(&obj->pushST))
            {
                StackPush(&obj->popST, StackTop(&obj->pushST));
                StackPop(&obj->pushST);
            }
    
        }
    
    }
    
    int myQueuePop(MyQueue* obj) {
        PushSTtoPopST(obj);
    
        int ret = StackTop(&obj->popST);
        StackPop(&obj->popST);
        return ret;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    队列判空

    其实元素出队列和获取队头元素都需要先判断队列是否为空,只不过这道题保证了空队列不会调用pop和peek函数。而判空其实很简单,只要两个栈都为空,那队列不就为空了吗。稍微注意一下,函数返回值是bool类型,如果队列为空就返回真,如果队列不为空就返回假。

    bool myQueueEmpty(MyQueue* obj) {
        return StackEmpty(&obj->popST) && StackEmpty(&obj->pushST);
    }
    
    • 1
    • 2
    • 3

    获取队头元素

    要先把pushST的元素全部导入到popST中再取队头元素。

    int myQueuePeek(MyQueue* obj) {
        PushSTtoPopST(obj);
        return StackTop(&obj->popST);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    释放队列

    要先把两个栈给释放掉,再释放掉整个队列结构。

    void myQueueFree(MyQueue* obj) {
        StackDestory(&obj->pushST);
        StackDestory(&obj->popST);
        free(obj);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

  • 相关阅读:
    药物滥用第五篇介绍
    常见的SQL在线练习平台
    ECharts数据可视化项目【10】
    12-面试官:如何使用线程池执行定时任务?
    Vue.js入门教程(三)
    SpringBoot配置文件
    创造建材数字转型新视界,中建材如何多边赋能集团业务快速发展
    PHP笔记-解决网站CDN加速后图片出现跨越问题
    第六章(6):Python中的函数—闭包和装饰器
    Java Stream流的详解
  • 原文地址:https://blog.csdn.net/weixin_61561736/article/details/126418568