🌹个人主页🌹:喜欢草莓熊的bear
🌹专栏🌹:数据结构
前言
本节内容是利用“ 队列 ”先进先出的特点 实现 “ 栈 ” 先进后出。
一、题目
1.1 题目描述:
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push
、top
、pop
和 empty
)。
实现
MyStack
类:
void push(int x)
将元素 x 压入栈顶。int pop()
移除并返回栈顶元素。int top()
返回栈顶元素。boolean empty()
如果栈是空的,返回true
;否则,返回false
。注意:
- 你只能使用队列的标准操作 —— 也就是
push to back
、peek/pop from front
、size
和is empty
这些操作。- 你所使用的语言也许不支持队列。 你可以使用 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 <= x <= 9
- 最多调用
100
次push
、pop
、top
和empty
- 每次调用
pop
和top
都保证栈不为空
1.2 分析题目
我们要通过队列实现栈,怎么实现呢?我们发现一个队列无论如何都无法实现栈的功能,所以我们就尝试创建两个队列来试试。分别为 empty(为空的队列) 、 noempty(不为空的队列)。我们把noempty的数据导入到empty的数据里面,也就是在两个队列里面进行数据倒换。文字比较抽象,所以接下来看图帮助理解。
二、模拟“ 栈 ”实现的功能
2.1 MyStack* myStackCreate()//初始化
根据我们之前对题目的分析可以知道我们要创建两个队列,所以我们就在结构体里面定义两个队列。
typedef struct //匿名结构体
{Queue s1;//创建两个队列Queue s2;} MyStack;
再对里面的结构体的队列进行初始化!,因为我们前面写的队列是基于单链表完成,要动态开辟空间。所以要malloc一下。具体操作如下:
MyStack* myStackCreate()//初始化
{MyStack* pst = (MyStack* )malloc(sizeof(MyStack));if(pst==NULL){perror("malloc fail");return -1;}QueueInit(&(pst->s1));QueueInit(&(pst->s2));return pst;
}
2.2 myStackPush(MyStack* obj, int x)//插入数据
我们要进行插入数据,就要想明白。我们要实现栈的特点 “ 后进先出 ”。我们这里插入数据任何一个队列中都是一样的。所以我们分为,当两个队列都是空时,进行随便插入。如果一个队列有数据那就在这个有数据的队列进行继续插入。代码很简单,要理解为什么这样插入。
void myStackPush(MyStack* obj, int x)//插入数据
{if(!QueueEmpty(&(obj->s1))){QueuePush(&(obj->s1),x);//如果s1里面有数据就继续进行数据插入}else{QueuePush(&(obj->s2),x);//如果是s1为空那么就向s2里面插入数据}}
2.3 myStackPop(MyStack* obj)//删除并且返回栈定元素
我们这里要实现删除栈顶元素并返回栈顶元素。我们这里采用了之前用到过的假设法,我们把不为空的队列里面数据倒换到为空的队列,这样我们就只需要把不为空里面的数据进行pop(删除)就可以了,因为还要返回栈顶元素 so 我们要把最后一个数据储存后进行pop在返回栈顶元素。
千万注意要把不为空里面数据pop!!
int myStackPop(MyStack* obj)//删除并且返回栈定元素
{//假设法MyStack* empty = &(obj->s1);MyStack* nonempty = &(obj->s2);if(!QueueEmpty(&(obj->s1))){empty = &(obj->s2);nonempty = &(obj->s1);}while(QueueSize(nonempty) > 1 ){QueuePush(empty,QueueFront(nonempty));QueuePop(nonempty);}int ret = QueueFront(nonempty);QueuePop(nonempty);return ret;
}
2.4 myStackTop(MyStack* obj) //获取栈顶元素
获取栈顶元素就很简单了,直接返回队列的最后一个数据就可以了。在这之前我们判一下空,不然一个空队列里面都没有数据怎么返回栈顶元素。
int myStackTop(MyStack* obj) //获取栈顶元素
{if(!QueueEmpty(&obj->s1)){return QueueBack(&obj->s1);}else{return QueueBack(&obj->s2);}
}
2.5 myStackEmpty(MyStack* obj) //判空
因为判空用到的地方比较多建议早点写他! 很简单我们把两个队列与一下在返回就可以了。
return QueueEmpty(&obj->s1) && QueueEmpty(&obj->s2);
2.6 myStackFree(MyStack* obj) //销毁
销毁我们要小心一点,因为我们不仅仅动态申请了Mystack的空间,我们还动态申请了队列的空间。所以两个队列也要进行销毁。我们直接调用我们之前写的队列销毁函数后,进行free操作。
还要进行置为空指针。
void myStackFree(MyStack* obj) //销毁
{QueueDestory(&obj->s1);QueueDestory(&obj->s2);free(obj);obj=NULL;
}
三、代码展示
typedef int QDataType;typedef struct QueueNode
{struct QueueNode* next;QDataType val;
}QNode;typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;void QueueInit(Queue* pq)
{assert(pq);pq->phead = pq->ptail = NULL;pq->size = 0;
}void QueueDestory(Queue* pq)
{assert(pq);QNode* pur = pq->phead;while (pur){QNode* cur = pur->next;free(pur);pur = cur;}pq->phead = pq->ptail = NULL;pq->size = 0;
}void QueuePush(Queue* pq, QDataType x)
{assert(pq);QNode* Newnode = (QNode*)malloc(sizeof(QNode));if (Newnode == NULL){perror("malloc fail");return;}Newnode->next = NULL;Newnode->val = x;if (pq->phead==NULL)//空链表{pq->phead = pq->ptail = Newnode;}else{pq->ptail->next = Newnode;pq->ptail = Newnode;}pq->size++;//用来计数
}void QueuePop(Queue* pq)
{assert(pq);assert(pq->phead);if (pq->phead == pq->ptail)//只有一个节点{free(pq->phead);pq->phead = pq->ptail = NULL;}else//多个节点{QNode* tmp = pq->phead->next;free(pq->phead);pq->phead = tmp;}pq->size--;
}QDataType QueueFront(Queue* pq)
{assert(pq);assert(pq->phead);return pq->phead->val;
}QDataType QueueBack(Queue* pq)
{assert(pq);assert(pq->ptail);return pq->ptail->val;
}int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;
}typedef struct //匿名结构体
{Queue s1;//创建两个队列Queue s2;} MyStack;MyStack* myStackCreate()//初始化
{MyStack* pst = (MyStack* )malloc(sizeof(MyStack));if(pst==NULL){perror("malloc fail");return -1;}QueueInit(&(pst->s1));QueueInit(&(pst->s2));return pst;
}void myStackPush(MyStack* obj, int x)//插入数据
{if(!QueueEmpty(&(obj->s1))){QueuePush(&(obj->s1),x);}else{QueuePush(&(obj->s2),x);}}int myStackPop(MyStack* obj)//删除并且返回栈定元素
{//假设法MyStack* empty = &(obj->s1);MyStack* nonempty = &(obj->s2);if(!QueueEmpty(&(obj->s1))){empty = &(obj->s2);nonempty = &(obj->s1);}while(QueueSize(nonempty) > 1 ){QueuePush(empty,QueueFront(nonempty));QueuePop(nonempty);}int ret = QueueFront(nonempty);QueuePop(nonempty);return ret;
}int myStackTop(MyStack* obj) //获取栈顶元素
{if(!QueueEmpty(&obj->s1)){return QueueBack(&obj->s1);}else{return QueueBack(&obj->s2);}
}bool myStackEmpty(MyStack* obj) //判空
{return QueueEmpty(&obj->s1) && QueueEmpty(&obj->s2);
}void myStackFree(MyStack* obj) //销毁
{QueueDestory(&obj->s1);QueueDestory(&obj->s2);free(obj);obj=NULL;
}
总结
我们这里的代码都是基于队列来实现的,我们要掌握这个倒换数据思路来解题。好了谢谢大家的观看!!下期见ヾ(•ω•`)o