代码随想录 10.02 || 栈与队列 LeetCode 232.用栈实现队列、 225.用队列实现栈

        今日的内容是“栈与队列理论基础”,栈是先进先出,队列是先进后出。力扣232和225题,主要考察对于栈和队列这两种数据结构的理解。在开始题目之前,从C和C++的角度,需要关注以下四个问题:

        1. 在 C++ 中 stack 和 queue 是容器吗?(不是容器,是容器适配器)
        2. 我们使用的 stack 是属于哪个版本的 STL?(存在多个版本,基础 HP STL,VC PJ STL,和 SGI STL,被 Linux 的 C++ 编译器 GCC 所采用)
        3. 我们使用的 STL 中 stack 是如何实现的?(默认实现为双向队列 deque 为缺省情况下,限制 deque 的一部分接口,实现栈的数据结构)
        4. 在 C++ 中,stack 提供迭代器来遍历 stack 空间吗?(不提供迭代器 iterator 遍历 stack 空间)

力扣232.用栈实现队列

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

        void push(int x):将元素 x 推到队列的末尾;

        int pop():从队列的开头移除并返回元素;

        int peek():返回队列开头的元素;

        boolean empty():判定队列是否为空,如果为空返回 true,非空返回 true。

class MyQueue { // C++
public:
    stack<int> stIn;
    stack<int> stOut;

    MyQueue() {
        
    }
    
    void push(int x) {
        stIn.push(x);
    }
    
    int pop() {
        if (stOut.empty()) {
            while (!stIn.empty()) {
                stOut.push(stIn.top());
                stIn.pop();
            }
        }
        int result = stOut.top();
        stOut.pop();
        return result;
    }
    
    int peek() {
        int res = this->pop();
        stOut.push(res);
        return res;
    }
    
    bool empty() {
        return stIn.empty() && stOut.empty();
    }
};

        上面给出C++的实现,代码十分简单,主要是对于栈和队列的理解。在实现的 MyQueue 类中,我们定义了两个栈的成员变量,然后实现了若干成员函数,支持队列的操作。进队、取队首和判空都很简单,只有出队稍有复杂。因为队列要求先进先出,而栈只能先进后出,所以我们利用两个栈,输入栈和输出栈,当进栈时,向输入栈压入数据,当出栈时,将输入栈的数据压入输出栈,然后从输出栈栈顶出栈,一正一反,实现队列的先进先出。C++实现了很多栈的功能函数,对于栈和队列之间的关系表达的较为晦涩,这里我又实现了C语言版本:

typedef struct { // C
    int stackInTop, stackOutTop;
    int stackIn[100], stackOut[100];
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* queue = (MyQueue*)malloc(sizeof(MyQueue));
    queue->stackInTop = 0;
    queue->stackOutTop = 0;
    return queue;
}

void myQueuePush(MyQueue* obj, int x) {
    if(obj->stackInTop != 100) {
        obj->stackIn[obj->stackInTop++] = x;
    }
}

int myQueuePop(MyQueue* obj) {
    int stackInTop = obj->stackInTop;
    int stackOutTop = obj->stackOutTop;

    if(stackOutTop == 0) {
        while(stackInTop != 0) {
            obj->stackOut[stackOutTop++] = obj->stackIn[--stackInTop];
        }
    }

    int top = obj->stackOut[--stackOutTop];
    obj->stackInTop = stackInTop;
    obj->stackOutTop = stackOutTop;
    return top;
}

int myQueuePeek(MyQueue* obj) {
    if(obj->stackOutTop != 0) {
        return obj->stackOut[obj->stackOutTop - 1];
    }
    return obj->stackIn[0];
}

bool myQueueEmpty(MyQueue* obj) {
    return obj->stackInTop == 0 && obj->stackOutTop == 0;
}

void myQueueFree(MyQueue* obj) {
    obj->stackInTop = 0;
    obj->stackOutTop = 0;
}

        在C语言版本中,可以很明显的看到的栈的一些操作,进栈,出栈,判空,取栈顶,对于栈顶指针的移动和释放栈空间。相较于C++,C的实现更为具体一点。

力扣225.用队列实现栈

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

        void push(int x):将元素 x 压入栈顶;

        int pop():移除并返回栈顶元素;

        int top():返回栈顶元素;

        boolean empty():如果栈是空的,返回 true,否则,返回 false。

class MyStack { // C++
public:
    queue<int> que1;
    queue<int> que2;

    MyStack() {

    }
    
    void push(int x) {
        que1.push(x);
    }
    
    int pop() {
        int size = que1.size();
        size--;
        while (size--) {
            que2.push(que1.front());
            que1.pop();
        }
        int result = que1.front();
        que1.pop();
        que1 = que2;
        while (!que2.empty()) {
            que2.pop();
        }
        return result;
    }
    
    int top() {
        return que1.back();
    }
    
    bool empty() {
        return que1.empty();
    }
};

        基于C++的实现,主要的操作还是在于出栈,使用两个先进先出的队列,实现后进先出的栈。为了实现先进后出,在每次需要出栈的时候,我们使用一个备份队列,将除最后一个元素之外的所有元素,入队,然后将最后一个元素出队,再将备份队列中的元素出队并入队到原队列。备份队列的作用和 temp 变量一样,暂存元素。既然如此,我们通过一个队列,直接将除最后一个元素之外的所有元素,出队再重新入队,使最后一个元素变为队首,也同样能实现后进先出。

class MyStack { // C++
public:
    queue<int> que;

    MyStack() {

    }

    void push(int x) {
        que.push(x);
    }

    int pop() {
        int size = que.size();
        size--;
        while (size--) {
            que.push(que.front());
            que.pop();
        }
        int result = que.front();
        que.pop();
        return result;
    }

    int top() {
        return que.back();
    }

    bool empty() {
        return que.empty();
    }
};

        在C++中可以轻便地使用一个队列实现栈,在C中则相对费劲,因为本质上 queue 是基于动态数组实现的,数据结构的长度可以动态变化,添加或删除一个元素为 O(1) 的时间复杂度。而在C语言中,基于静态数组实现的队列,需要使用 front 指针标识当前队首的位置,当出队过多,会造成过多的无效内存空间;如果不使用 front 指针,则每当出队的时候都需要前移后面所有的元素,时间复杂度为 O(n),当然也可以通过动态分配内存的方式,实现动态数组的队列,但是较为复杂,且每次队列长度发生变化,都需要 realloc。下面仅给出基于C的两个队列实现栈的代码:

typedef struct { // C
    int front1, rear1;
    int front2, rear2;
    int queue1[100], queue2[100];
} MyStack;

MyStack* myStackCreate() {
    MyStack* stack = (MyStack*)malloc(sizeof(MyStack));

    stack->front1 = 0;
    stack->rear1 = 0;

    stack->front2 = 0;
    stack->rear2 = 0;

    return stack;
}

void myStackPush(MyStack* obj, int x) {
    obj->queue1[obj->rear1++] = x;
}

int myStackPop(MyStack* obj) {
    int front1 = obj->front1, rear1 = obj->rear1;
    int front2 = obj->front2, rear2 = obj->rear2;

    while(front1 != rear1 - 1) {
        obj->queue2[rear2++] = obj->queue1[front1++];
    }
    
    int result = obj->queue1[front1];
    front1 = 0;
    rear1 = 0;

    while(front2 != rear2) {
        obj->queue1[rear1++] = obj->queue2[front2++];
    }
    front2 = 0;
    rear2 = 0;

    obj->front1 = front1;
    obj->rear1 = rear1;
    obj->front2 = front2;
    obj->rear2 = rear2;

    return result;
}

int myStackTop(MyStack* obj) {
    return obj->queue1[obj->rear1 - 1];
}

bool myStackEmpty(MyStack* obj) {
    return obj->front1 == obj->rear1;
}

void myStackFree(MyStack* obj) {
    obj->front1 = 0;
    obj->rear1 = 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值