用队列实现栈 <难度系数⭐>

967 阅读5分钟

「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战

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

实现 MyStack 类:

1️⃣ void push(int x) 将元素 x 压入栈顶。

2️⃣ int pop() 移除并返回栈顶元素。

3️⃣ int top() 返回栈顶元素。

4️⃣ boolean empty() 如果栈是空的,返回 true ;否则,返回 false

⚠ 注意

1️⃣ 你只能使用队列的基本操作——也就是push to back、peek/pop from front、size和is empty这些操作。

2️⃣ 你所使用的语言也许不支持队列。你可以使用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️⃣ 1 <= x <= 9

2️⃣ 最多调用100 次 push、pop、top 和 empty

3️⃣ 每次调用 pop 和 top 都保证栈不为空

⚜ 进阶 你能否实现每种操作的均摊时间复杂度为 O(1) 的栈?换句话说,执行 n 个操作的总时间复杂度 O(n) ,尽管其中某个操作可能需要比其他操作更长的时间。你可以使用两个以上的队列。

🧷 平台:Visual studio 2017 && windows

🔑 核心思想:队列的数据是不能从队尾出的,只能从队头出,而这里要实现的是队列实现栈,所以只能遵循栈的特性——后进先出。这里就需要另外一个队列,具体步骤如下:

1、一个队列有数据,一个队列没数据

2、入数据时向不为空的那个入

3、出数据时,就将不为空的队列的前 size-1 个拷贝至另一个队列,然后再Pop掉剩下的一个数据

leetcode原题

//声明
    //结构体
typedef int QDataType;
typedef struct QueueNode
{
    struct QueueNode* next; //指向下一个节点
    QDataType data; //存储整型数据
}QueueNode;

typedef struct Queue
{
    QueueNode* phead;//头指针
    QueueNode* ptail;//尾指针
}Queue;

    //函数
void QueueInit(Queue* pq); 
void QueuePush(Queue* pq, QDataType x);	
bool QueueEmpty(Queue* pq);
void QueuePop(Queue* pq);
QDataType QueueSize(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
void QueueDestory(Queue* pq);
//函数实现
void QueueInit(Queue* pq)
{
    assert(pq);
    //把2个指针置空
    pq->phead = pq->ptail = NULL;
}
void QueuePush(Queue* pq, QDataType x)
{
    assert(pq);
    //malloc空间,如果需要频繁的开辟空间建议再实现一个BuyQueueNode用于malloc
    QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
    if (newnode == NULL)
    {
	printf("malloc fail\n");
	exit(-1);
    }
    newnode->data = x;
    newnode->next = NULL;
    //第一次插入
    if (pq->phead == NULL)
    {
	pq->phead = pq->ptail = newnode;
    }
    //非第一次插入
    else
    {
	pq->ptail->next = newnode;
	pq->ptail = newnode;
    }
}
bool QueueEmpty(Queue* pq)
{
    assert(pq);
    //空链表返回true,非空链表返回false
    return pq->phead == NULL;
}
void QueuePop(Queue* pq)
{
    assert(pq);
    //链表为空时不能删除
    assert(!QueueEmpty(pq));
    //只有一个节点的情况
    if (pq->phead->next == NULL)
    {
	free(pq->phead);
	pq->phead = pq->ptail = NULL;
    }
    //多个节点的情况
    else
    {
	QueueNode* next = pq->phead->next;
	free(pq->phead)	;
	pq->phead = next;
    }
}
QDataType QueueSize(Queue* pq)
{
    assert(pq);
    //如果需要频繁的调用QueueSize这个接口,可以在Queue这个结构体中增加一个成员用于记录长度
    int sz = 0;
    QueueNode* cur = pq->phead;
    while (cur)
    {
	sz++;
	cur = cur->next;
    }
    return sz;
}
QDataType QueueFront(Queue* pq)
{
    assert(pq);
    //链表为空时不能取头
    assert(!QueueEmpty(pq));

    return pq->phead->data;
}
QDataType QueueBack(Queue* pq)
{
    assert(pq);
    //链表为空时不能取尾
    assert(!QueueEmpty(pq));

    return pq->ptail->data;
}
void QueueDestory(Queue* pq)
{
    assert(pq);
	
    QueueNode* cur = pq->phead;
    //遍历链表
    while (cur)
    {
	QueueNode* next = cur->next;
	free(cur);
	cur = next;
    }
    pq->phead = pq->ptail = NULL;
}

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

/** Initialize your data structure here. */

MyStack* myStackCreate() 
{
    //malloc空间
    MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
    //Init两个队列
    QueueInit(&pst->q1);
    QueueInit(&pst->q2);
    return pst;
}

/** Push element x onto stack. */
void myStackPush(MyStack* obj, int x) 
{
    assert(obj);
    //QueueEmpty为空时返回true,不为空时返回false
        //往不为空的那个队列里插入数据(q1不为空往q1插入,q2不为空往q2插入)
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1, x);
    }
    else
    {
        QueuePush(&obj->q2, x);
    }
}

/** Removes the element on top of the stack and returns that element. */
int myStackPop(MyStack* obj) 
{
    assert(obj);
    //先默认q1为空,q2不为空
    Queue* emptyQ = &obj->q1;
    Queue* nonemptyQ = &obj->q2;
    //q1不为空,重新赋值
    if(!QueueEmpty(&obj->q1))
    {
        emptyQ = &obj->q2;
        nonemptyQ = &obj->q1;
    }
    //拷贝 - 将非空队列的size-1个数据拷贝
    while(QueueSize(nonemptyQ) > 1)
    {
        //将非空的队列拷贝至空的队列
        QueuePush(emptyQ, QueueFront(nonemptyQ));
        //删除迭代
        QueuePop(nonemptyQ);
    }
    //top记录非空队列的剩下一个值
    int top = QueueFront(nonemptyQ);
    //删除非空队列的剩下一个数据,这个数据就是栈顶的数据
    QueuePop(nonemptyQ);
    //返回
    return top;
}

/** Get the top element. */
int myStackTop(MyStack* obj) 
{
    assert(obj);
    //q1不为空,取q1的数据
    if(!QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }
    //q2不为空,取q2的数据
    else
    {
        return QueueBack(&obj->q2);
    }
}

/** Returns whether the stack is empty. */
bool myStackEmpty(MyStack* obj) 
{
    assert(obj);
    //q1和q2一定有一个为空
    //q1为空返回真,q2为空返回真,mystackEmpty为空返回真;
    //q1为空返回真,q2为非空返回假,myStackEmpty为非空,返回假
    //q1为非空返回假,q2为空返回真,myStackEmpty为非空,返回假
    return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}

void myStackFree(MyStack* obj) 
{
    assert(obj);
    //结合上面的代码分析我们需要回收两个队列和myStackcreate里malloc的空间
    QueueDestory(&obj->q1);
    QueueDestory(&obj->q2);

    free(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);
*/