【C】队列与栈的相互转换

[复制链接]
发表于 2025-10-26 17:04:44 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
  栈与队列是两种特点相反的数据布局,一个特点是后进先出,一个特点是先辈先出,但是他们之间是可以相互转换的。

目次
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)。
我们再来看一下标题中所给的函数:
  1. typedef struct {
  2.    
  3. } MyStack;
  4. MyStack* myStackCreate() {
  5.    
  6. }
  7. void myStackPush(MyStack* obj, int x) {
  8.    
  9. }
  10. int myStackPop(MyStack* obj) {
  11.    
  12. }
  13. int myStackTop(MyStack* obj) {
  14.    
  15. }
  16. bool myStackEmpty(MyStack* obj) {
  17.    
  18. }
  19. void myStackFree(MyStack* obj) {
  20.    
  21. }
复制代码
  显然,这个题是想要让我们通过两个队列来实现一个栈,此中栈具有初始化(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) 代码

  1. typedef int QDataType;
  2. //定义队列节点的结构
  3. typedef struct QueueNode
  4. {
  5.         QDataType data;
  6.         struct QueueNode* next;
  7. }QNode;
  8. typedef struct Queue
  9. {
  10.         QNode* phead;//对头 -- 删除数据
  11.         QNode* ptail;//队尾 -- 插入数据
  12. }Queue;
  13. //队列的初始化
  14. void QueueInit(Queue* pq)
  15. {
  16.         assert(pq);
  17.         pq->phead = pq->ptail = NULL;
  18. }
  19. //队列的销毁
  20. void QueueDestroy(Queue* pq)
  21. {
  22.         assert(pq);
  23.         QNode* pcur = pq->phead;
  24.         while (pcur)
  25.         {
  26.                 QNode* next = pcur->next;
  27.                 free(pcur);
  28.                 pcur = next;
  29.         }
  30.         pq->phead = pq->ptail = NULL;
  31. }
  32. //入队
  33. void QueuePush(Queue* pq, QDataType x)
  34. {
  35.         assert(pq);
  36.         QNode* newnode = (QNode*)malloc(sizeof(QNode));
  37.         if (newnode == NULL)
  38.         {
  39.                 perror("malloc fail!\n");
  40.                 exit(1);
  41.         }
  42.         newnode->data = x;
  43.         newnode->next = NULL;
  44.         //如果队列为空
  45.         if (pq->phead == NULL)
  46.         {
  47.                 pq->phead = pq->ptail = newnode;
  48.         }
  49.         else
  50.         {
  51.                 //队列不为空
  52.                 pq->ptail->next = newnode;
  53.                 pq->ptail = pq->ptail->next;
  54.         }
  55. }
  56. //判断是否为空
  57. bool QueueEmpty(Queue* pq)
  58. {
  59.         assert(pq);
  60.         return pq->phead == NULL;
  61. }
  62. //出队
  63. void QueuePop(Queue* pq)
  64. {
  65.         assert(pq);
  66.         assert(!QueueEmpty(pq));
  67.         //如果只有一个节点
  68.         if (pq->phead->next == NULL)
  69.         {
  70.                 free(pq->phead);
  71.                 pq->phead = pq->ptail = NULL;
  72.         }
  73.         else
  74.         {
  75.                 QNode* next = pq->phead->next;
  76.                 free(pq->phead);
  77.                 pq->phead = next;
  78.         }
  79. }
  80. //取队尾元素
  81. QDataType QueueBack(Queue* pq)
  82. {
  83.         assert(pq);
  84.         assert(!QueueEmpty(pq));
  85.         return pq->ptail->data;
  86. }
  87. //取对头元素
  88. QDataType QueueFront(Queue* pq)
  89. {
  90.         assert(pq);
  91.         assert(!QueueEmpty(pq));
  92.         return pq->phead->data;
  93. }
  94. //返回元素个数
  95. int QueueSize(Queue* pq)
  96. {
  97.         assert(pq);
  98.         int size = 0;
  99.         QNode* pcur = pq->phead;
  100.         while (pcur)
  101.         {
  102.                 size++;
  103.                 pcur = pcur->next;
  104.         }
  105.         return size;
  106. }
  107. ////////////////////////数据结构队列///////////////////////////
  108. typedef struct {
  109.     //创建两个队列
  110.     Queue q1;
  111.     Queue q2;
  112. } MyStack;
  113. MyStack* myStackCreate()
  114. {
  115.     MyStack* st = (MyStack*)malloc(sizeof(MyStack));
  116.     QueueInit(&(st->q1));
  117.     QueueInit(&(st->q2));
  118.     return st;
  119. }
  120. void myStackPush(MyStack* obj, int x)
  121. {
  122.     //往非空队列里面插入数据
  123.     if (!QueueEmpty(&(obj->q1)))
  124.     {
  125.         QueuePush(&(obj->q1), x);
  126.     }
  127.     else{
  128.         QueuePush(&(obj->q2), x);
  129.     }
  130. }
  131. bool myStackEmpty(MyStack* obj)
  132. {
  133.     //只要判断两个队列为不为空就可以
  134.     return QueueEmpty(&(obj->q1)) && QueueEmpty(&(obj->q2));
  135. }
  136. int myStackPop(MyStack* obj)
  137. {
  138.     //把非空队列的除最后一个元素之外的元素入队到另一个队列
  139.     Queue* pn = &(obj->q1);
  140.     Queue* ph = &(obj->q2);
  141.     if (QueueEmpty(&(obj->q2)))
  142.     {
  143.         pn = &(obj->q2);
  144.         ph = &(obj->q1);
  145.     }
  146.     while (QueueSize(ph) > 1)
  147.     {
  148.         //入空队列
  149.         QueuePush(pn, QueueFront(ph));
  150.         //出队
  151.         QueuePop(ph);
  152.     }
  153.     //把最后一个元素出队
  154.     int ret = QueueFront(ph);
  155.     QueuePop(ph);
  156.     return ret;
  157. }
  158. int myStackTop(MyStack* obj)
  159. {
  160.     //返回非空队列的队尾元素
  161.     if (!QueueEmpty(&(obj->q1)))
  162.     {
  163.         return QueueBack(&(obj->q1));
  164.     }
  165.     else
  166.     {
  167.         return QueueBack(&(obj->q2));
  168.     }
  169. }
  170. void myStackFree(MyStack* obj)
  171. {
  172.     QueueDestroy(&(obj->q1));   
  173.     QueueDestroy(&(obj->q2));
  174.     free(obj);
  175.     obj = NULL;   
  176. }
复制代码

2  用栈来实现队列

leetcode链接
https://leetcode.cn/problems/implement-queue-using-stacks/submissions/601751470/
1) 标题剖析

  请你仅使用两个栈实现先入先出队列。队列应当支持一样寻常队列支持的全部利用(push、pop、peek、empty)。
  再来看一下标题中所给的函数:
  1. typedef struct {
  2.    
  3. } MyQueue;
  4. MyQueue* myQueueCreate() {
  5.    
  6. }
  7. void myQueuePush(MyQueue* obj, int x) {
  8.    
  9. }
  10. int myQueuePop(MyQueue* obj) {
  11.    
  12. }
  13. int myQueuePeek(MyQueue* obj) {
  14.    
  15. }
  16. bool myQueueEmpty(MyQueue* obj) {
  17.    
  18. }
  19. void myQueueFree(MyQueue* obj) {
  20.    
  21. }
复制代码
   显然,这个也是像用两个队列实现一个栈一样,是用两个栈来实现一个队列,这个队列包罗以下函数:界说布局(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) 代码

  1. typedef int STDataType;
  2. //定义栈的结构--用数组来实现
  3. typedef struct Stack
  4. {
  5.         STDataType* arr;
  6.         int top;//指向栈顶
  7.         int capacity;//容量
  8. }Stack;
  9. //初始化
  10. void StackInit(Stack* ps)
  11. {
  12.         assert(ps);
  13.         ps->arr = NULL;
  14.         ps->capacity = ps->top = 0;
  15. }
  16. //销毁
  17. void StackDestroy(Stack* ps)
  18. {
  19.         assert(ps);
  20.         if (ps->arr)
  21.                 free(ps->arr);
  22.         ps->capacity = ps->top = 0;
  23. }
  24. //入栈
  25. void StackPush(Stack* ps, STDataType x)
  26. {
  27.         assert(ps);
  28.         if (ps->top == ps->capacity)
  29.         {
  30.                 //增容
  31.                 int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
  32.                 STDataType* tmp = (STDataType*)realloc(ps->arr, sizeof(STDataType) * newCapacity);
  33.                 if (tmp == NULL)
  34.                 {
  35.                         perror("realloc fail!\n");
  36.                         exit(1);
  37.                 }
  38.                 ps->arr = tmp;
  39.                 ps->capacity = newCapacity;
  40.         }
  41.         ps->arr[ps->top++] = x;
  42. }
  43. //判空
  44. bool StackEmpty(Stack* ps)
  45. {
  46.         assert(ps);
  47.         return ps->top == 0;
  48. }
  49. //出栈
  50. void StackPop(Stack* ps)
  51. {
  52.         assert(ps);
  53.         assert(!StackEmpty(ps));
  54.         ps->top--;
  55. }
  56. //取栈顶元素
  57. STDataType StackTop(Stack* ps)
  58. {
  59.         assert(!StackEmpty(ps));
  60.         return ps->arr[ps->top - 1];
  61. }
  62. //有效元素个数
  63. int StackSize(Stack* ps)
  64. {
  65.         assert(ps);
  66.         return ps->top;
  67. }
  68. ////////////////////////////////数据结构栈/////////////////////////////////////////////
  69. typedef struct {
  70.     //定义两个栈,一个用来当做入队的队列,另一个当做出队的队列
  71.     Stack pushst;
  72.     Stack popst;
  73. } MyQueue;
  74. MyQueue* myQueueCreate()
  75. {
  76.     MyQueue* q = (MyQueue*)malloc(sizeof(MyQueue));
  77.     if (q == NULL)
  78.     {
  79.         perror("malloc fail!\n");
  80.         exit(1);
  81.     }
  82.     //初始化队列中的两个栈
  83.     StackInit(&q->pushst);
  84.     StackInit(&q->popst);
  85.     return q;
  86. }
  87. void myQueuePush(MyQueue* obj, int x)
  88. {
  89.     //将数据往入队的栈里面入栈
  90.     StackPush(&obj->pushst, x);
  91. }
  92. int myQueuePop(MyQueue* obj)
  93. {
  94.     //如果出队的栈为空,那就把入队的栈的数据全部入栈到出队的栈   
  95.     if (StackEmpty(&obj->popst))
  96.     {
  97.         while (StackSize(&obj->pushst) > 0)
  98.         {
  99.             //取栈顶元素
  100.             STDataType tmp = StackTop(&obj->pushst);
  101.             //出栈
  102.             StackPop(&obj->pushst);
  103.             //入栈
  104.             StackPush(&obj->popst, tmp);
  105.         }
  106.     }
  107.     STDataType ret = StackTop(&obj->popst);
  108.     StackPop(&obj->popst);
  109.     return ret;
  110. }
  111. int myQueuePeek(MyQueue* obj)
  112. {
  113.     //如果出队的栈为空,那就把入队的栈的数据全部入栈到出队的栈   
  114.     if (StackEmpty(&obj->popst))
  115.     {
  116.         while (StackSize(&obj->pushst) > 0)
  117.         {
  118.             //取栈顶元素
  119.             STDataType tmp = StackTop(&obj->pushst);
  120.             //出栈
  121.             StackPop(&obj->pushst);
  122.             //入栈
  123.             StackPush(&obj->popst, tmp);
  124.         }
  125.     }
  126.     //不需要出队就可以
  127.     STDataType ret = StackTop(&obj->popst);
  128.     return ret;
  129. }
  130. bool myQueueEmpty(MyQueue* obj)
  131. {
  132.     //如果连个栈都为空,那么队列就为空
  133.     return StackEmpty(&obj->popst) && StackEmpty(&obj->pushst);
  134. }
  135. void myQueueFree(MyQueue* obj)
  136. {
  137.     //销毁两个栈就可以
  138.     if (!StackEmpty(&obj->popst))
  139.     {
  140.         StackDestroy(&obj->popst);
  141.     }
  142.     if (!StackEmpty(&obj->pushst))
  143.     {
  144.         StackDestroy(&obj->pushst);
  145.     }
  146.     //最后别忘了释放obj
  147.     free(obj);
  148.     obj = NULL;
  149. }
复制代码

  通过栈与队列的相互转换,信赖各人对于栈和队列的明确会更加深入。

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表