「这是我参与11月更文挑战的第10天,活动详情查看:2021最后一次更文挑战」
📝 题述:请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:
1️⃣ void push(int x) 将元素 x 推到队列的末尾。
2️⃣ int pop() 从队列的开头移除并返回元素。
3️⃣ int top() 返回队列开头的元素。
4️⃣ boolean empty() 如果队列是空的,返回 true ;否则,返回 false
⚠ 注意
1️⃣ 你只能使用标准的栈操作 —— 也就是只有push to top,peek/pop from top,和 is empty 操作是合法的。
2️⃣ 你所使用的语言也许不支持栈。你可以使用 list 或者 deque (双端队列) 来模拟一个栈,只要是标准的栈操作即可。
⚜ 进阶
你能否实现每个操作均摊时间复杂度为0(1)的队列?换句话说,执行 n 个操作的总时间复杂度为o(n),即使其中一个操作可能花费较长时间。
💨 示例:
输入:
["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️⃣ 1 <= x <= 9
2️⃣ 最多调用100 次 push、pop、top 和 empty
3️⃣ 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)
🧷 平台:Visual studio 2017 && windows
🔑 核心思想:
1、入数据,进 pushst
2、出数据,看 popst 是否为空,如果为空,就先把 pushst 的数据倒过来,然后出数据;如果不为空,则直接出 popst 的数据
//一、声明
//结构体
typedef int STDatatype;
typedef struct Stack
{
STDatatype* a; //指向动态开辟的空间
int top; //栈顶
int capacicy; //容量
}ST;
//函数
//初始化
void StackInit(ST* ps);
//插入
void StackPush(ST* ps, STDatatype x);
//判空
bool StackEmpty(ST* ps);
//删除
void StackPop(ST* ps);
//长度
int StackSize(ST* ps);
//栈顶
STDatatype StackTop(ST* ps);
//销毁
void StackDestory(ST* ps);
//二、实现
void StackInit(ST* ps)
{
assert(ps);
//初始化
ps->a = NULL;
ps->top = 0;
ps->capacicy = 0;
}
void StackPush(ST* ps, STDatatype x)
{
assert(ps);
//检查空间,满了就增容
if (ps->top == ps->capacicy)
{
//第一次开辟空间容量为4,其它次容量为当前容量*2
int newcapacity = ps->capacicy == 0 ? 4 : ps->capacicy * 2;
//第一次开辟空间,a指向空,realloc的效果同malloc
STDatatype* tmp = realloc(ps->a, sizeof(STDatatype) * newcapacity);
//检查realloc
//realloc失败
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
//realloc成功
ps->a = tmp;
ps->capacicy = newcapacity;
}
//插入数据
ps->a[ps->top] = x;
ps->top++;
}
bool StackEmpty(ST* ps)
{
assert(ps);
//等于0是真,否则为假
return ps->top == 0;
}
void StackPop(ST* ps)
{
assert(ps);
//删除的话得保证指向的空间不为空
assert(!StackEmpty(ps));
//删除
--ps->top;
}
int StackSize(ST* ps)
{
assert(ps);
//此时的top就是长度
return ps->top;
}
STDatatype StackTop(ST* ps)
{
assert(ps);
//找栈顶的话得保证指向的空间不为空
assert(!StackEmpty(ps));
//此时的top-1就是栈顶数据
return ps->a[ps->top - 1];
}
void StackDestory(ST* ps)
{
assert(ps);
//a为真代表它指向动态开辟的空间
if (ps->a)
{
free(ps->a);
}
ps->a = NULL;
ps->top = 0;
ps->capacicy = 0;
}
typedef struct
{
ST pushST;
ST popST;
} MyQueue;
/** Initialize your data structure here. */
//malloc空间
MyQueue* myQueueCreate()
{
//malloc一块MyQueue类型大小的空间
MyQueue* q = (MyQueue*)malloc(sizeof(MyQueue));
//初始化
StackInit(&q->pushST);
StackInit(&q->popST);
//返回MyQueue这块空间的地址
return q;
}
/** Push element x to the back of queue. */
//插入
void myQueuePush(MyQueue* obj, int x)
{
assert(obj);
//往pushST这个结构体里插入
StackPush(&obj->pushST, x);
}
/** Get the front element. */
//取队头
int myQueuePeek(MyQueue* obj)
{
assert(obj);
//如果popST为空,则倒pushST的数据,再取队头
if(StackEmpty(&obj->popST))
{
//popST内有数据,返回false,再非
while(!StackEmpty(&obj->pushST))
{
//把pushST栈顶的数据插入至popST
StackPush(&obj->popST, StackTop(&obj->pushST));
//迭代
StackPop(&obj->pushST);
}
}
//如果popST不为空,直接取队头
return StackTop(&obj->popST);
}
/** Removes the element from in front of queue and returns that element. */
//删除
int myQueuePop(MyQueue* obj)
{
assert(obj);
//如果popST为空,则倒pushST的数据,再出数据
if(StackEmpty(&obj->popST))
{
//popST内有数据,返回false,再非
while(!StackEmpty(&obj->pushST))
{
//把pushST栈顶的数据插入至popST
StackPush(&obj->popST, StackTop(&obj->pushST));
//迭代
StackPop(&obj->pushST);
}
}
//备份popST内栈顶的数据,用于返回
int front = StackTop(&obj->popST);
//如果popST不为空,直接出数据
StackPop(&obj->popST);
//返回popST栈顶的数据
return front;
}
/** Returns whether the queue is empty. */
//判空
bool myQueueEmpty(MyQueue* obj)
{
assert(obj);
//pushST和popST同时为空,才为空
return StackEmpty(&obj->pushST) && StackEmpty(&obj->popST);
}
//回收
void myQueueFree(MyQueue* obj)
{
assert(obj);
//上面的代码中,我们先malloc了一块MyQueue类型的空间,在插入的操作接口中又malloc了pushST和popST
StackDestory(&obj->pushST);
StackDestory(&obj->popST);
free(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);
*/