题目的要求是用两个队列实现栈,首先我们要考虑队列的特点:先入先出,栈的特点:后入先出,所以我们的目标就是如何让先入栈的成员后出栈,后入栈的成员先出栈。
因为有两个队列,于是我们可以这样想:让 队列1 的成员除最后一个成员出队列到 队列2,这时 队列1 剩下的成员不就是要出栈的成员吗?(即后入先出)那么我们如何控制让 队列1 出队列到只剩下一个成员呢?我们可以使用size函数,即 size(队列1) 是1的时候再Pop或者Peek,就是出栈。如图所示:
我没有提到入栈,入栈其实就是把数据按照顺序放进 队列1 中,因为队列和栈在存储数据方面都是顺序存放的,只有在出数据的时候顺序不同,这里的 队列1 就可以理解为栈的拷贝,队列2 就可以理解为出栈的工具,因为只有在出栈时才会占用 队列2 。
Pop完或者Peek查看完并没有结束,我们要把 队列2 中的成员再归还到 队列1 中,如果是Pop(出栈函数,删除栈顶数据),那么 队列2 直接出队列到 队列1 即可,如果是Peek(查看栈顶数据,不删除),那么 队列1 中的成员要先出队列到 队列2 在执行出队列到 队列1 的操作,如图:
接下来是代码实现,
首先还是创建栈结构体和结构体中的两个队列:
struct QueueList {int val;struct QueueList* next;
};
struct Queue {struct QueueList* head;struct QueueList* tail;
};
typedef struct {struct Queue* q1;struct Queue* q2;
} MyStack;MyStack* myStackCreate() {MyStack* stack=(MyStack*)malloc(sizeof(MyStack));stack->q1=(struct Queue*)malloc(sizeof(struct Queue));stack->q2=(struct Queue*)malloc(sizeof(struct Queue));QueueInit(stack->q1);QueueInit(stack->q2);return stack;
}
主要是最后两块代码,创建栈结构体并且为栈申请空间。这里我一开始犯了一个错误,没有给每个队列的指针申请空间,导致q1和q2是野指针,所以也提醒了我一次malloc是为两个指针存放开辟空间, 但并没有为指针指向的位置开辟空间,导致野指针的问题。所以要二次malloc为队列指针开辟空间。
接着是入栈函数:
void myStackPush(MyStack* obj, int x) {QueuePushBack(obj->q1,x);
}
直接就是把数据放进 队列1 q1中去。
然后是Pop(出栈函数,删除栈顶)和Peek(查看栈顶成员函数):
int myStackPop(MyStack* obj) {while(Queue_size(obj->q1)>1){QueuePushBack(obj->q2,QueueFrontPop(obj->q1));}int val=QueueFrontPop(obj->q1);while(Queue_size(obj->q2)>0){QueuePushBack(obj->q1,QueueFrontPop(obj->q2));}return val;
}int myStackTop(MyStack* obj) {while(Queue_size(obj->q1)>1){QueuePushBack(obj->q2,QueueFrontPop(obj->q1));}int val=QueueFrontPop(obj->q1);QueuePushBack(obj->q2,val);while(Queue_size(obj->q2)>0){QueuePushBack(obj->q1,QueueFrontPop(obj->q2));}return val;
}
每个函数中都有两个while循环,第一个是将 队列1 q1 的成员拷贝到 队列2 q2 ,第二个是将 队列2 q2 的成员拷贝到 队列1 q1。
先解释一下Pop函数,根据刚才的流程图,当size>1时,就是说只有一个成员时停止拷贝,这时把最后的值Pop掉并记录,然后当size>0时,就是说把 q2 的成员全部拷贝回 q1,然后返回Pop掉的值。
Peek函数只改变了一点,就是Pop改为Peek,记录下栈顶成员,然后接着把 q1 拷贝回 q2,再整个队列拷贝回 q2。
最后是检查是否为空 Is_empty 函数和销毁内存函数:
bool myStackEmpty(MyStack* obj) {if(Queue_size(obj->q1)==0){return true;}else{return false;}
}void myStackFree(MyStack* obj) {QueueDes(obj->q1);QueueDes(obj->q2);free(obj);
}
因为每次调用函数过后 队列1 q1 就相当于栈,所以只需要检查 队列1 是否为空即可。
这就是文章的全部内容了,希望对你有所帮助,如有错误欢迎评论。