生命不是要等待风暴过去,而是要学会在风暴中跳舞。 ——卡莉尔·吉布朗
目录
🍁一.栈实现队列
🍀二.使用两个栈实现队列的功能
🌼1.在队列的结构体中创建两个栈
🚁2.创建一个队列的结构体指针
🌉3.myQueuePush入队列操作
🌏4.myQueuePeek返回队列头的元素
🍐5.myQueuePop删除队列头的元素并返回元素
🌳6.myQueueEmpty判断队列是否为空
🍅7.myQueueFree销毁队列
🏵️三.完整代码
题目描述:
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push
、pop
、peek
、empty
):
实现 MyQueue
类:
void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false
示例 1:
输入:
["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
注意这里的pop和peek函数同样是功能差不多的,都是返回队列头的元素,只是pop函数还要删除队列头的元素。
接口函数:
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) {
}
做题链接:栈实现队列
🍁一.栈实现队列
🍀二.使用两个栈实现队列的功能
做题思路:同样和队列模拟实现栈一样,我们都是使用两个,但是两个栈来实现队列更加的容易,我们知道栈是先进后出,而队列是先进先出。我们使用两个栈,一个栈只入元素,而另一个栈只出元素,如何理解呢?这个入数据的的栈把元素往出数据的栈里面倒元素,那么这些元素就反过来了,头就变成了尾,为就变成了头,这样出元素的那个栈就变成队列的功能了。
画图理解:
然后我们就把1 2 3 4 5往入元素的栈依次入栈即可。
然后就是把入元素的栈的元素往出元素的栈里面给倒元素,依次往里面入元素。
此时出元素的栈依次出元素,出的顺序就变成了 1 2 3 4 5,而入的顺序也是1 2 3 4 5,这恰恰就是队列的功能啊,先进先出。
思路是有了,最主要还是看如何写代码。
🌼1.在队列的结构体中创建两个栈
typedef struct {
Stack pushst;//入元素的栈
Stack popst;//出元素的栈
} MyQueue;
🚁2.创建一个队列的结构体指针
同样这里不是传参,而是以返回值的方式返回结构体的指针。
MyQueue* myQueueCreate() {
MyQueue*obj=(MyQueue*)malloc(sizeof(MyQueue));
if(obj==NULL)
return NULL;
StackInit(&obj->pushst);//注意这里->的优先级高于&,obj先和pushst结合,再是&
StackInit(&obj->popst);//和这样写是一样的&(obj->popst)
return obj;
}
🌉3.myQueuePush入队列操作
入队列的方式就很简单了,因为只有一个栈是入栈操作的,直接把元素往里面入即可。
void myQueuePush(MyQueue* obj, int x) {
StackPush(&obj->pushst,x);
}
🌏4.myQueuePeek返回队列头的元素
这个就需要把入元素的栈的元素往出元素的栈里面给倒元素,然后返回这个栈顶的元素,就相当于队列头的元素。
这里注意要好好理解这个代码的意思。
int myQueuePeek(MyQueue* obj)
{
if(StackEmpty(&obj->popst))//出元素的栈为空,那么就需要倒数据,再返回栈顶的元素
{
while(!StackEmpty(&obj->pushst))//非空就继续倒元素
{
StackPush(&obj->popst,StackTop(&obj->pushst));
StackPop(&obj->pushst);
}
}
//出元素的栈不为空,直接返回栈顶的元素即可
return StackTop(&obj->popst);//返回栈顶的元素,就相当于队列头的元素
}
🍐5.myQueuePop删除队列头的元素并返回元素
这个函数和myQueuePeek函数的功能是差不多的,只是这个函数需要删除队列头的元素,我们可以直接复用这个函数。
int myQueuePop(MyQueue* obj)
{
int top=myQueuePeek(obj);
StackPop(&obj->popst);//删除元素
return top;
}
🌳6.myQueueEmpty判断队列是否为空
bool myQueueEmpty(MyQueue* obj) {
return StackEmpty(&obj->pushst)//同样需要两个栈都为空,队列才为空
&&StackEmpty(&obj->popst);
}
🍅7.myQueueFree销毁队列
void myQueueFree(MyQueue* obj) {
StackDestroy(&obj->pushst);//销毁入元素的栈
StackDestroy(&obj->popst);//销毁出元素的栈
free(obj);//释放结构体的指针
}
🏵️三.完整代码
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top; // 栈顶
int Capacity; // 容量
}Stack;
// 初始化栈
void StackInit(Stack* ps);
// 入栈
void StackPush(Stack* ps, STDataType x);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);
// 初始化栈
void StackInit(Stack* ps)
{
assert(ps);
ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);//动态的开辟空间
if (ps->a == NULL)
{
perror("malloc\n");
return;
}
ps->top = 0;
ps->Capacity = 4;
}
// 入栈
void StackPush(Stack* ps, STDataType x)
{
assert(ps);
if (ps->top == ps->Capacity)
{
STDataType* temp = (STDataType*)realloc(ps->a, sizeof(STDataType) * ps->Capacity * 2);
if (temp == NULL)
{
perror("realloc\n");
return;
}
ps->Capacity *= 2;//每次增容尾上一次的二倍
ps->a = temp;
}
ps->a[ps->top] = x;
ps->top++;//栈内入一个数据,top就要往上面走一步
}
// 出栈
void StackPop(Stack* ps)
{
assert(ps);
assert(ps->top>0);
ps->top--;
}
// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
assert(ps);
return ps->a[ps->top-1];
}
// 销毁栈
void StackDestroy(Stack* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = ps->Capacity = 0;
}
// 获取栈中有效元素个数
int StackSize(Stack* ps)
{
assert(ps);
return ps->top;
}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps) {
assert(ps);
return ps->top==0;
}
typedef struct {
Stack pushst;//入元素的栈
Stack popst;//出元素的栈
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue*obj=(MyQueue*)malloc(sizeof(MyQueue));
if(obj==NULL)
return NULL;
StackInit(&obj->pushst);//注意这里->的优先级高于&,obj先和pushst结合,再是&
StackInit(&obj->popst);//和这样写是一样的&(obj->popst)
return obj;
}
void myQueuePush(MyQueue* obj, int x) {
StackPush(&obj->pushst,x);
}
int myQueuePop(MyQueue* obj)
{
int top=myQueuePeek(obj);
StackPop(&obj->popst);
return top;
}
int myQueuePeek(MyQueue* obj)
{
if(StackEmpty(&obj->popst))//出元素的栈为空,那么就需要倒数据,再返回栈顶的元素
{
while(!StackEmpty(&obj->pushst))//非空就继续倒元素
{
StackPush(&obj->popst,StackTop(&obj->pushst));
StackPop(&obj->pushst);
}
}
//出元素的栈不为空,直接返回栈顶的元素即可
return StackTop(&obj->popst);//返回栈顶的元素,就相当于队列头的元素
}
bool myQueueEmpty(MyQueue* obj) {
return StackEmpty(&obj->pushst)
&&StackEmpty(&obj->popst);
}
void myQueueFree(MyQueue* obj) {
StackDestroy(&obj->pushst);
StackDestroy(&obj->popst);
free(obj);
}