• 栈与队列经典题目——用队列实现栈


    本篇文章讲解栈和队列这一部分知识点的经典题目:用栈实现队列、用队列实现栈。对应的题号分别为:Leetcode.225——用队列实现栈,。

    在对两个题目进行解释之前,先回顾以下栈和队列的特点与不同:

    栈是一种特殊的线性表,并且只能在尾部进行插入、删除的操作。对于栈的实现,可以通过顺序表或者链表的思路来达成。但是,参考栈只能在尾部进行插入、删除操作的特点。一般采用顺序表进行实现。

    队列也是一种特殊的线性表,只能在队尾进行插入操作,在队头进行删除操作。鉴于队列的这一性质,一般采用链表来实现队列。

    1.Leetcode.225——用队列实现栈:

    题目如下:

    1.1 思路分析:

    给出下列一个栈:


    在栈中,遵从后进先出的原则。但是,本题要求是利用队列来实现栈。对于队列来说,出数据只能从队头进行。题目中要求利用两个队列来实现栈的功能,对于本功能,思路如下:
    给定下面两个队列,分别命名为queue1,queue2

    按照题目中的要求,需要移除元素4。对于队列来说,移除元素只能从队头进行。所以,先把queue1中的元素1,2,3都移动到queue2中。此时效果如下:

    此时,再对queue1进行一次取队头元素的操作即可。 下面为了方便表达,将queue1简称为q1,queue2简称为q2

    由上述分析可知。解决本题的关键就是在使用两个队列时,需要让一个队列中存储元素,另一个队列保持为空。当需要进行返回栈顶元素的操作时,再让为空的队列保存另一个队列中的前N-1项元素。所以,q1,q2一个队列用于存储元素,一个用于保持空状态为了方便表达。下面,会默认创建两个结构体指针:empty,来存储q1的地址,noempty来存储q2的地址。并在后续会针对二者谁为空进行判断。

    (注:下面只给出各种给定功能的实现方法,在进行解题时,需要预先将编写好的xiami码复制到题目上方,本文采用一起学数据结构(6)——栈和队列_起床写代码啦!的博客-CSDN博客

    中的队列) 

    1.2 各功能的实现:

     1.2.1 栈的创建及初始化myStackCreate

    前面说到,需要一个用于存储元素的队列,一个保持空状态的队列。但是对于二者谁为空,在后续的操作myStackPush中进行判断即可。在本功能中不需要进行判断。代码如下:

    1. //创建队列
    2. typedef struct {
    3. Que q1;
    4. Que q2;
    5. } MyStack;
    6. //初始化队列,注意,返回值返回地址,需要采用malloc返回以保证返回时不会因为变量的局部性成为野指针
    7. MyStack* myStackCreate() {
    8. MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
    9. QueueInit(&obj->q1);
    10. QueueInit(&obj->q2);
    11. return obj;
    12. }

    1.2.2 向栈中插入元素myStackPush

    为了保证empty为空,noempty不为空,所以,在向栈中插入元素时,需要向noempty中插入。在初始化这一步骤中,并没有分辨哪个队列为空,在本步骤并不需要明确知道哪个队列为空,只需要利用QueueEmpty函数判断队列q1,q2是否为空,如果q1为空,此时q1empty,直接向q2中进行插入,反之则向q1中插入,代码如下:

    1. void myStackPush(MyStack* obj, int x) {
    2. if(!QueueEmpty(&obj->q1))
    3. {
    4. QueuePush(&obj->q1,x);
    5. }
    6. else
    7. {
    8. QueuePush(&obj->q2,x);
    9. }
    10. }

    1.2.3 移除并返回栈顶元素 myStackPop:

    在思路分析中,已经给出了该功能的实现方法。即,让noempty指向的队列中的前N-1项元素移动到empty所对应的元素。在移动元素之前,需要先判断q1,q2哪个队列为空。方法如下:

    首先创建结构体指针emptynoempty。让二者分别指向队列q1,q2。利用QueueEmpty函数判断此时的empty是否为空,若为空,则不做改变。若不为空,则令emptynoempty中存储的地址交换。

    代码如下:

    1. int myStackPop(MyStack* obj) {
    2. Que* noempty = &obj->q1;
    3. Que* empty = &obj->q2;
    4. if(!QueueEmpty(empty))
    5. {
    6. noempty = &obj->q2;
    7. empty = &obj->q1;
    8. }
    9. }

    再判断出q1,q2哪个队列为empty,哪个队列为noempty后,进行下一步。首先,利用QueueFront函数取出noempty中的队头元素,再利用QueuePush函数将QueueFront取出的元素插入到noempty中。

    题目要求,移除并且返回。所以需要额外创建一个变量Top用于存储栈顶元素。之后再利用QueuePop函数移除栈顶元素,最后返回Top即可。代码如下:
     

    1. int myStackPop(MyStack* obj) {
    2. Que* noempty = &obj->q1;
    3. Que* empty = &obj->q2;
    4. if(!QueueEmpty(empty))
    5. {
    6. noempty = &obj->q2;
    7. empty = &obj->q1;
    8. }
    9. while( QueueSize(noempty) > 1)
    10. {
    11. QueuePush(empty,QueueFront(noempty));
    12. QueuePop(noempty);
    13. }
    14. int Top = QueueFront(noempty);
    15. QueuePop(noempty);
    16. return Top;
    17. }

    1.2.4 返回栈顶元素myStackTop

    栈顶元素所对应的位置就是队列的队尾。所以,只需要采用向栈中插入元素的方法,通过QueueEmpty函数,对不满足QueueEmpty的队列(即非空队列)调用QueueBack函数,返回函数的返回值即可。代码如下:

    1. int myStackTop(MyStack* obj) {
    2. if(!QueueEmpty(&obj->q1))
    3. {
    4. return QueueBack(&obj->q1);
    5. }
    6. else
    7. {
    8. return QueueBack(&obj->q2);
    9. }
    10. }

    1.2.5 探空myStackEmpty:

    原理较为简单,只给出代码:

    1. bool myStackEmpty(MyStack* obj) {
    2. return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
    3. }

    1.2.6 释放动态开辟的空间myStackFree:
    代码如下:

    1. void myStackFree(MyStack* obj) {
    2. QueueDestory(&obj->q1);
    3. QueueDestory(&obj->q2);
    4. free(obj);
    5. }

    2.结果展示及题解代码总览:

    2.1 结果展示:


     

    2.2 题解代码总览:

    1. typedef int QDataType;
    2. typedef struct QueueNode
    3. {
    4. struct QueueNode* next;
    5. QDataType data;
    6. }QNode;
    7. typedef struct Queue
    8. {
    9. QNode* phead;
    10. QNode* tail;
    11. int size;
    12. }Que;
    13. //初始化
    14. void QueueInit(Que* ps);
    15. //销毁
    16. void QueueDestory(Que* ps);
    17. //插入元素
    18. void QueuePush(Que* ps, QDataType x);
    19. //删除元素
    20. void QueuePop(Que* ps);
    21. //取头部元素
    22. QDataType QueueFront(Que* ps);
    23. //取尾部元素
    24. QDataType QueueBack(Que* ps);
    25. //探空
    26. bool QueueEmpty(Que* ps);
    27. //求长度
    28. int QueueSize(Que* ps);
    29. void QueueInit(Que* ps)
    30. {
    31. assert(ps);
    32. ps->phead = ps->tail = 0;
    33. ps->size = 0;
    34. }
    35. void QueuePush(Que* ps, QDataType x)
    36. {
    37. assert(ps);
    38. QNode* newnode = (QNode*)malloc(sizeof(QNode));
    39. if (newnode == NULL)
    40. {
    41. perror("malloc");
    42. exit(-1);
    43. }
    44. newnode->next = NULL;
    45. newnode->data = x;
    46. if (ps->tail == NULL)
    47. {
    48. ps->phead = ps->tail = newnode;
    49. }
    50. else
    51. {
    52. ps->tail->next = newnode;
    53. ps->tail = newnode;
    54. }
    55. ps->size++;
    56. }
    57. void QueuePop(Que* ps)
    58. {
    59. assert(ps);
    60. assert(!QueueEmpty(ps));
    61. if (ps->phead->next == NULL)
    62. {
    63. free(ps->phead);
    64. ps->phead = ps->tail = NULL;
    65. }
    66. else
    67. {
    68. QNode* next = ps->phead->next;
    69. free(ps->phead);
    70. ps->phead = next;
    71. }
    72. ps->size--;
    73. }
    74. QDataType QueueFront(Que* ps)
    75. {
    76. assert(ps);
    77. assert(!QueueEmpty(ps));
    78. return ps->phead->data;
    79. }
    80. QDataType QueueBack(Que* ps)
    81. {
    82. assert(ps);
    83. assert(!QueueEmpty(ps));
    84. return ps->tail->data;
    85. }
    86. bool QueueEmpty(Que* ps)
    87. {
    88. assert(ps);
    89. return ps->phead == NULL;
    90. }
    91. int QueueSize(Que* ps)
    92. {
    93. assert(ps);
    94. return ps->size;
    95. }
    96. void QueueDestory(Que* ps)
    97. {
    98. assert(ps);
    99. QNode* cur = ps->phead;
    100. while (cur)
    101. {
    102. QNode* next = cur->next;
    103. free(cur);
    104. cur = next;
    105. }
    106. ps->phead = ps->tail = NULL;
    107. ps->size = 0;
    108. }
    109. //创建队列
    110. typedef struct {
    111. Que q1;
    112. Que q2;
    113. } MyStack;
    114. //初始化队列,注意,返回值返回地址,需要采用malloc返回以保证返回时不会因为变量的局部性成为野指针
    115. MyStack* myStackCreate() {
    116. MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
    117. QueueInit(&obj->q1);
    118. QueueInit(&obj->q2);
    119. return obj;
    120. }
    121. void myStackPush(MyStack* obj, int x) {
    122. if(!QueueEmpty(&obj->q1))
    123. {
    124. QueuePush(&obj->q1,x);
    125. }
    126. else
    127. {
    128. QueuePush(&obj->q2,x);
    129. }
    130. }
    131. //思路:将非空队列中前N-1项元素移到空队列中
    132. int myStackPop(MyStack* obj) {
    133. Que* noempty = &obj->q1;
    134. Que* empty = &obj->q2;
    135. if(!QueueEmpty(empty))
    136. {
    137. noempty = &obj->q2;
    138. empty = &obj->q1;
    139. }
    140. while( QueueSize(noempty) > 1)
    141. {
    142. QueuePush(empty,QueueFront(noempty));
    143. QueuePop(noempty);
    144. }
    145. int Top = QueueFront(noempty);
    146. QueuePop(noempty);
    147. return Top;
    148. }
    149. int myStackTop(MyStack* obj) {
    150. if(!QueueEmpty(&obj->q1))
    151. {
    152. return QueueBack(&obj->q1);
    153. }
    154. else
    155. {
    156. return QueueBack(&obj->q2);
    157. }
    158. }
    159. bool myStackEmpty(MyStack* obj) {
    160. return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
    161. }
    162. void myStackFree(MyStack* obj) {
    163. QueueDestory(&obj->q1);
    164. QueueDestory(&obj->q2);
    165. free(obj);
    166. }



     


     

  • 相关阅读:
    组合总和 (递归回溯+剪枝)
    基于springboot+vue的前后端分离房屋租赁信息网站
    CompletableFuture原理与实践-外卖商家端API的异步化
    ubuntu20.04安装MySQL8、MySQL服务管理、mysql8卸载
    wifi指纹室内定位系统 计算机竞赛
    TI AM3352/54/59 工业核心板硬件说明书
    Linux用户管理常用命令及对应配置文件
    Linux:【1】Linux中的文件权限概念和相关命令
    数据治理-数据管理角色
    大模型Prompt-Tuning技术入门
  • 原文地址:https://blog.csdn.net/2301_76836325/article/details/132888836