马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
栈与队列是两种特点相反的数据布局,一个特点是后进先出,一个特点是先辈先出,但是他们之间是可以相互转换的。
目次
1 用队列实现栈
1) 标题剖析
2) 算法剖析
(1) 布局(MyStack)
(2) 初始化(myStackCreate)
(3) 入栈(myStackPush)
(4) 出栈(myStackPop)
(5) 取栈顶元素(myStackTop)
(6)判空(myStackEmpty)
(7) 烧毁栈(myStackFree)
3) 代码
2 用栈来实现队列
1) 标题剖析
2) 算法剖析
3) 代码
1 用队列实现栈
leetcode链接https://leetcode.cn/problems/implement-stack-using-queues/
1) 标题剖析
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持平凡栈的全部四种利用(push、top、pop 和 empty)。
我们再来看一下标题中所给的函数:
- typedef struct {
-
- } MyStack;
- MyStack* myStackCreate() {
-
- }
- void myStackPush(MyStack* obj, int x) {
-
- }
- int myStackPop(MyStack* obj) {
-
- }
- int myStackTop(MyStack* obj) {
-
- }
- bool myStackEmpty(MyStack* obj) {
-
- }
- void myStackFree(MyStack* obj) {
-
- }
复制代码 显然,这个题是想要让我们通过两个队列来实现一个栈,此中栈具有初始化(myStackCreate)、入栈(myStackPush)、出栈(myStackPop)、取栈顶元素(myStackTop)、判空(myStackEmpty)以及烧毁栈(myStackFree),只不外这里须要注意是Pop的返回值为int,也就是要返回栈顶元素。
2) 算法剖析
要完成用队列实现栈我们应该充实思量他们俩之间的特点。接下来是我们来看这四个几个函数的实现:
(1) 布局(MyStack)
标题中说了用两个队列来实现一个栈,以是MyStack内里只须要有两个队列就可以了,我们将这两个队列定名为q1 和 q2。
(2) 初始化(myStackCreate)
上面的函数要求我们返回一个 MyStack 的指针,以是起首我们须要用 malloc 函数开辟一块 MyStack 的空间,然后初始化该布局内里的两个队列就可以了,末了返回谁人指针即可。
(3) 入栈(myStackPush)
入栈的时间,我们选择往非空的队列内里入数据,如许会更好的共同出栈的逻辑。
(4) 出栈(myStackPop)
入栈的时间是不绝向非空的队列内里入数据,以是出栈的时间肯定会有一个空队列,一个非空队列,以是实验出栈利用的时间,我们可以让非空队列除队尾末了一个元素外的数据全都入到空队列里,然后老师存非空队列里的队尾末了一个数据,然后让末了一个数据出队列,返回这个值即可,其过程如图所示:
通过两个队列之间把数据往返变更,就可以实现数据的后入先出,而且如许也可以包管出栈之后,还是一个空队列和一个非空队列,下一次入栈和出栈的时间也不会出标题。
(5) 取栈顶元素(myStackTop)
既然入栈的时间有一个空队列和一个非空队列,要取到栈顶元素,也就是末了一个入栈的数据,这里只须要返回非空队列的队尾数据就可以了。
(6)判空(myStackEmpty)
判空很简朴,只需判断两个队列 q1 和 q2 是否都为空就可以了,假如都为空,那就返回 true,假如都不为空,那就返回 false。
(7) 烧毁栈(myStackFree)
烧毁栈就是烧毁布局中的两个队列,只须要调用 QueueDestroy 烧毁两个队列就可以了,只不外须要注意的是在初始化的时间开辟了一块 MyStack 的空间,以是末了不要忘记把这块空间也开释掉。
3) 代码
2 用栈来实现队列
leetcode链接https://leetcode.cn/problems/implement-queue-using-stacks/submissions/601751470/
1) 标题剖析
请你仅使用两个栈实现先入先出队列。队列应当支持一样寻常队列支持的全部利用(push、pop、peek、empty)。
再来看一下标题中所给的函数:
- 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) {
-
- }
复制代码 显然,这个也是像用两个队列实现一个栈一样,是用两个栈来实现一个队列,这个队列包罗以下函数:界说布局(MyQueue)、初始化(myQueueCreate)、入队(myQueuePush)、出队(myQueuePop)、取队头元素(myQueuePeek)、判空(myQueueEmpty) 以及烧毁队列(myQueueFree)。
2) 算法剖析
(1) 布局(MyQueue)
像用队列实现栈一样,这里也是界说 MyQueue 也是界说两个栈,这里定名为pushst与 popst,一个用来入数据,一个用来出数据。
(2) 初始化(myQueueCreate)
这里初始化也是让我们返回一个 MyQueue 布局的指针,以是起首先开辟一块 MyQueue 布局巨细的空间,然后让内里的两个栈初始化就可以了。
(3) 入队(myQueuePush)
入队比力简朴,直接往 pushst 内里插入数据即可。
(4) 出队(myQueuePop)
出队的时间分两种环境:
a. 假如 popst 不为空,那就直接让 popst 的栈顶元素出栈,然后返回刚才出栈的栈顶元素。
b. 假如 popst 为空,那就先依次将 pushst的栈顶元素入到 popst 内里,直到 pushst 为空,然后再让 popst 出栈,再返回出栈的栈顶元素。
如先入队1, 2, 3, 4 四个数据,然后出队1,再入队 5 ,再出队 2 的过程如图所示:
通过先向 pushst 内里入数据,再将 pushst 里的数据入栈到 popst 内里,如许颠末两次先辈后出的调解数据,数据就会变成先辈先出,如上面谁人图,刚开始 pushst 内里由栈顶到栈底的数据为 4,3,2,1,但是入到 popst 内里,栈顶到栈底的数据就变成了1,2,3,4,如许就实现了数据的先入先出。
(5) 取队头元素(myQueuePeek)
取队头元素是雷同于出栈的过程的,只不外不须要将 popst 的栈顶元素出栈,直接返回 popst 的栈顶数据即可,依然分两种环境:
a. 假如 popst 不为空,那就直接返回 popst 的栈顶元素。
b. 假如 popst 为空,那就先依次将 pushst 的栈顶元素入到 popst 内里,直到 pushst 为空,然后返回 popst 的栈顶元素。
(6) 判空(myQueueEmpty)
判空和用队列实现栈一样,判断 MyQueue 内里的两个栈是否同时为空即可,假如都为空,那么返回 true;假如不为空,那么返回 false。
(7) 烧毁队列(myQueueFree)
烧毁队列也只需烧毁底层的两个栈 pushst 和 popst 即可,只不外须要注意要让开辟出的 MyQueue 的那一块空间也开释掉,才不会出现内存走漏的环境。
3) 代码
通过栈与队列的相互转换,信赖各人对于栈和队列的明确会更加深入。
|