目录
💓 博客主页:C-SDN花园GGbond
⏩ 文章专栏:数据结构经典题目刨析(c语言)
一.题目描述
二.解题思路
首先这道题需要我们使用两个队列来完成栈的实现, 这里我们的思路是, 栈的要求是后进先出, 而队列是先进先出, 让两个队列来回导数据, 插入数据时, 插入到不为空的队列中, 如果需要出数据, 先让不为空的队列的前n-1个数据导入到为空的队列中, 然后在出数据, 此时正好就是最后一个数据, 也就是后入先出,
以下是使用两个队列实现栈的基本步骤和原理:
栈的结构定义:包含两个队列的结构
1.初始化:初始化两个空队列,在任意时刻,我们只会使用其中一个队列来进行入栈和出栈操作, 而另一个队列则保持为空。
2.入栈(Push):将元素添加到非空队列的末尾。
如果两个队列都为空,则选择任意一个队列添加元素。
3.出栈(Pop):
如果两个队列都为空,说明栈也为空,此时不能进行出栈操作。将非空队列中的元素(除了最后 一个)逐个出队并入队到另一个队列中,直到只剩下最后一个元 素。此时,该元素就是栈顶元 素,我们将其出队并返回。
4.查看栈顶元素(Peek):
如果两个队列都为空,说明栈也为空,此时不能查看栈顶元素。
如果队列的实现允许查看队尾数据,会比较简单,直接返回非空队列的队尾数据即可
如果队列实现只允许查看队首数据,那么也需要移动元素
我们将非空队列的元素(除了最后一个)逐个出队并入队到另一个队列中,直到只剩下最后一个 元素。此时,该元素就是栈顶元素,将其保存下来,入队到另一个队列中,并在本队列出队(这 样做是为了保持只有一个非空队列)然后返回该元素。
这里画图解释队列元素的移动过程(注意:为方便理解对队列的结构进行了简化)
三.代码实现
步骤如下
1.因为C语言没有自带的队列, 所以我们需要把我们实现的队列写进去, C++会自带的队列.这里我们直接导入
2.创建MyStack,里面需要两个队列, myStackCreate其实也就是我们的初始化, 这里不可以直接 MyStack s, 因为函数里面的创建的变量出了函数就被释放了 ,所以我们需要动态开辟空间. 分别进行初始化
typedef struct {
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate() {
MyStack* s = (MyStack*)malloc(sizeof(MyStack));
QueueInit(&s->q1);
QueueInit(&s->q2);
return s;
}
3.入栈, 哪个不为空, 我们就把元素插入到哪个队列, 这里我使用了假设法, 来找出不为空的队列.
void myStackPush(MyStack* obj, int x) {
assert(obj);
//假设法
Queue* Empty = &obj->q1;
Queue* nonEmpty = &obj->q2;
if(QueueEmpty(&obj->q2))
{
Empty = &obj->q2;
nonEmpty = &obj->q1;
}
//把数据插入到不为空的队列
QueuePush(nonEmpty,x);
}
4.出栈, 还是假设法, 找到不为空的队列, 然后通过为空的队列导一下,不要忘记找到数据之后, 让最后一个数据出队列.
int myStackPop(MyStack* obj) {
assert(obj);
Queue* Empty = &obj->q1;
Queue* nonEmpty = &obj->q2;
if(QueueEmpty(&obj->q2))
{
Empty = &obj->q2;
nonEmpty = &obj->q1;
}
//把不为空的队列的数据的前n-1个数据导入到为空的队列
while(QueueSize(nonEmpty)>1)
{
QueuePush(Empty,QueueFront(nonEmpty));
QueuePop(nonEmpty);
}
int top = QueueTail(nonEmpty);
QueuePop(nonEmpty);
return top;
}
5.剩下的几个方法总体来说比较简单, 代码如下,注意销毁操作, 我们手动开辟的空间都需要手动释放.
int myStackTop(MyStack* obj) {
assert(obj);
if(!QueueEmpty(&obj->q1))
{
return QueueTail(&obj->q1);
}
else{
return QueueTail(&obj->q2);
}
}
bool myStackEmpty(MyStack* obj) {
return (QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2));
}
void myStackFree(MyStack* obj) {
assert(obj);
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
}
完整代码
typedef int DataType;
typedef struct QueueNode
{
struct QueueNode* next;
DataType val;
}QNode;
typedef struct Queue
{
QNode* phead;
QNode* ptail;
int size;
}Queue;
void QueueInit(Queue* pq)
{
assert(pq);
pq->phead = NULL;
pq->ptail = NULL;
pq->size = 0;
}
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->phead;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->phead = pq->ptail = NULL;
pq->size = 0;
}
void QueuePush(Queue* pq, DataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail!");//perror函数在<stdio.h>头文件包含,标准错误流
return;
}
newnode->next = NULL;
newnode->val = x;
if (pq->ptail == NULL)
{
pq->phead = pq->ptail = newnode;
}
else
{
pq->ptail->next = newnode;
pq->ptail = newnode;
}
pq->size++;
}
void QueuePop(Queue* pq)
{
assert(pq!=NULL);//条件为真,程序继续
assert(pq->size!=0); //条件为真,程序继续
if (pq->phead->next == NULL)
{
free(pq->phead);
pq->phead = pq->ptail = NULL;
}
else
{
QNode* next = pq->phead->next;
free(pq->phead);
pq->phead = next;
}
pq->size--;
}
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->size == 0;
}
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
DataType QueueFront(Queue* pq)
{
assert(pq);
assert(pq->phead);
return pq->phead->val;
}
DataType QueueTail(Queue* pq)
{
assert(pq);
assert(pq->ptail);
return pq->ptail->val;
}
typedef struct {
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate() {
MyStack* s = (MyStack*)malloc(sizeof(MyStack));
QueueInit(&s->q1);
QueueInit(&s->q2);
return s;
}
void myStackPush(MyStack* obj, int x) {
assert(obj);
//假设法
Queue* Empty = &obj->q1;
Queue* nonEmpty = &obj->q2;
if(QueueEmpty(&obj->q2))
{
Empty = &obj->q2;
nonEmpty = &obj->q1;
}
//把数据插入到不为空的队列
QueuePush(nonEmpty,x);
}
int myStackPop(MyStack* obj) {
assert(obj);
Queue* Empty = &obj->q1;
Queue* nonEmpty = &obj->q2;
if(QueueEmpty(&obj->q2))
{
Empty = &obj->q2;
nonEmpty = &obj->q1;
}
//把不为空的队列的数据的前n-1个数据导入到为空的队列
while(QueueSize(nonEmpty)>1)
{
QueuePush(Empty,QueueFront(nonEmpty));
QueuePop(nonEmpty);
}
int top = QueueTail(nonEmpty);
QueuePop(nonEmpty);
return top;
}
int myStackTop(MyStack* obj) {
assert(obj);
if(!QueueEmpty(&obj->q1))
{
return QueueTail(&obj->q1);
}
else{
return QueueTail(&obj->q2);
}
}
bool myStackEmpty(MyStack* obj) {
return (QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2));
}
void myStackFree(MyStack* obj) {
assert(obj);
QueueDestroy(&obj->q1);
QueueDestroy(&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);
*/