• 猿创征文|栈和队列OJ刷题


    前言

    作者小蜗牛向前冲

    名言我可以接收失败,但我不能接收放弃

     如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正。

    为了提高自己编写代码的能力,特意开设刷题专题,记录自己刷题的思路和理解。欢迎❀大家的指正。

    在下面的解题中我们都用C语言实现。 

     1用队列实现栈

     在这里我们就是要将队列模拟实现成栈,我们知道队列是先进先出,栈是先进后出;那我们又如何实现呢?其实我们可以借助二个队列实现。下面我们借助图像来理解一下:

     

     首先我们建立二个队列p1,p2,我们可能理解为入栈我们就将入数据到p1处。

    其次,我们可以认为p2队列是用来中间存放数据的

    这样我们就成功将5出栈了,如果要将4出栈,那么我们又得需要将p2中的数据倒入到p1中:

     这样我们就完成了4出栈。

    下面我们简单总结一下思路:

    1我们要建立二个队列经行模拟。

    2始终保持一个队列为空,在出栈时,将将n-1个数据都倒入到空队列中,那么留在另个队列的数据就可以直接出栈了。

    下面是完成的解题代码:

    1. typedef int QDataType;
    2. //定义队列
    3. typedef struct QueueNode
    4. {
    5. QDataType data;//数据类型
    6. struct QueueNode* next;
    7. }QNode;
    8. //定义指向头和尾的二个指针
    9. typedef struct Queue
    10. {
    11. QNode* head;
    12. QNode* tail;
    13. int size;
    14. }Queue;
    15. //初始化
    16. void QueueInit(Queue* pq);
    17. //销毁
    18. void QueueDestroy(Queue* pq);
    19. //入队
    20. void QueuePush(Queue* pq, QDataType x);
    21. //出队
    22. void QueuePop(Queue* pq);
    23. //返回指向队头的数据的指针
    24. QDataType QueueFront(Queue* pq);
    25. //返回指向队尾的数据的指针
    26. QDataType QueueBack(Queue* pq);
    27. //判断队列是否为空
    28. bool QueueEmpty(Queue* pq);
    29. //返回队列的大小
    30. int QueueSize(Queue* pq);
    31. //初始化
    32. void QueueInit(Queue* pq)
    33. {
    34. assert(pq);
    35. pq->head = pq->tail = NULL;
    36. pq->size = 0;
    37. }
    38. //销毁
    39. void QueueDestroy(Queue* pq)
    40. {
    41. assert(pq);
    42. QNode* cur = pq->head;
    43. while (cur)
    44. {
    45. QNode* del = cur;
    46. cur = cur->next;//指向下个节点
    47. free(del);
    48. }
    49. pq->head = pq->tail = NULL;//防止出现野指针
    50. pq->size = 0;
    51. }
    52. //入队
    53. void QueuePush(Queue* pq, QDataType x)
    54. {
    55. assert(pq);
    56. //申请节点
    57. QNode* newNode = (QNode*)malloc(sizeof(QNode));
    58. if (newNode==NULL)
    59. {
    60. perror("malloc fail");
    61. exit(-1);
    62. }
    63. else
    64. {
    65. newNode->data = x;
    66. newNode->next = NULL;
    67. }
    68. //队列为空
    69. if (pq->tail == NULL)
    70. {
    71. pq->head = pq->tail = newNode;
    72. }
    73. //不为空
    74. else
    75. {
    76. pq->tail->next = newNode;
    77. pq->tail = newNode;//tail指针指向newNode
    78. }
    79. pq->size++;
    80. }
    81. //出队
    82. void QueuePop(Queue* pq)
    83. {
    84. assert(pq);
    85. //断言队列是否为空
    86. assert(!QueueEmpty(pq));
    87. //当队列中就一个数据时
    88. if (pq->head->next == NULL)
    89. {
    90. free(pq->head);
    91. pq->head = pq->tail = NULL;
    92. }
    93. else
    94. {
    95. QNode* del = pq->head;
    96. pq->head = pq->head->next;//头变为下个节点
    97. free(del);
    98. del = NULL;
    99. }
    100. pq->size--;
    101. }
    102. //判断队列是否为空
    103. bool QueueEmpty(Queue* pq)
    104. {
    105. assert(pq);
    106. return pq->tail == NULL;
    107. }
    108. //返回指向队头的数据的指针
    109. QDataType QueueFront(Queue* pq)
    110. {
    111. assert(pq);
    112. //断言队列是否为空
    113. assert(!QueueEmpty(pq));
    114. return pq->head->data;
    115. }
    116. //返回指向队尾的数据的指针
    117. QDataType QueueBack(Queue* pq)
    118. {
    119. assert(pq);
    120. //断言队列是否为空
    121. assert(!QueueEmpty(pq));
    122. return pq->tail->data;
    123. }
    124. //返回队列的大小
    125. int QueueSize(Queue* pq)
    126. {
    127. return pq->size;
    128. }
    129. typedef struct {
    130. Queue p1;//入栈
    131. Queue p2;//出栈
    132. } MyStack;
    133. MyStack* myStackCreate() {
    134. MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
    135. //对栈初始化
    136. QueueInit(&obj->p1);
    137. QueueInit(&obj->p2);
    138. return obj;
    139. }
    140. void myStackPush(MyStack* obj, int x) {
    141. //当p1为空时就将数据倒入
    142. if(!QueueEmpty(&obj->p1))
    143. {
    144. QueuePush(&obj->p1,x);
    145. }
    146. else
    147. {
    148. QueuePush(&obj->p2,x);
    149. }
    150. }
    151. int myStackPop(MyStack* obj) {
    152. Queue* empty = &obj->p1;//假设p1为空
    153. Queue* noEmpty = &obj->p2;
    154. //如果p1队列为非空
    155. if(!QueueEmpty(&obj->p1))
    156. {
    157. empty = &obj->p2;
    158. noEmpty = &obj->p1;
    159. }
    160. //将非空队列中的N-1的数据都倒入到空队列中,那么原队列还剩的1个数据就是要返回的栈顶数据
    161. while(QueueSize(noEmpty)>1)
    162. {
    163. QueuePush(empty,QueueFront(noEmpty));//入栈
    164. QueuePop(noEmpty);//出栈
    165. }
    166. int top = QueueFront(noEmpty);
    167. QueuePop(noEmpty);//出栈
    168. return top;
    169. }
    170. int myStackTop(MyStack* obj) {
    171. if(!QueueEmpty(&obj->p1))
    172. {
    173. return QueueBack(&obj->p1);
    174. }
    175. else
    176. {
    177. return QueueBack(&obj->p2);
    178. }
    179. }
    180. bool myStackEmpty(MyStack* obj) {
    181. return QueueEmpty(&obj->p1) && QueueEmpty(&obj->p2);
    182. }
    183. void myStackFree(MyStack* obj) {
    184. QueueDestroy(&obj->p1);
    185. QueueDestroy(&obj->p2);
    186. free(obj);
    187. }

     2 栈实现队列

    要用二个栈实现队列,这是很好实现的。

    为什么这么说呢?我们可以用栈PushST来模拟入队列栈PopST模拟出队列

    下面我们顺着这个思路来,来图解一下 1,2,3,4的入队列和出队列的过程。

    1数据入队列

     2 要出队列时,当PopST为空的时候,就将PushST的数据倒入到PopST中,然后直接出就行。

    完整代码:

    1. typedef int STDataType;
    2. //定义栈
    3. typedef struct Stack
    4. {
    5. STDataType* arr;//数据类型
    6. int pos;//数组下标
    7. int capacity;//栈的容量
    8. }ST;
    9. //初始化
    10. void StackInit(ST* ps);
    11. //销毁
    12. void StackDestroy(ST* ps);
    13. //入栈
    14. void StackPush(ST* ps, STDataType x);
    15. //出栈
    16. void StackPop(ST* ps);
    17. 显示返回栈顶数据
    18. STDataType StackTop(ST* ps);
    19. //判断栈是否为空
    20. bool StackEmpty(ST* ps);
    21. //返回栈的长度//初始化
    22. void StackInit(ST* ps)
    23. {
    24. assert(ps);
    25. ps->arr = NULL;//初始数组为空
    26. ps->pos = ps->capacity = 0;//初始为0
    27. }
    28. //销毁
    29. void StackDestroy(ST* ps)
    30. {
    31. assert(ps);
    32. free(ps->arr);//arr是整个栈的地址
    33. ps->arr = NULL;
    34. ps->capacity = ps->pos = 0;
    35. }
    36. //入栈
    37. void StackPush(ST* ps, STDataType x)
    38. {
    39. assert(ps);
    40. //判断栈的空间是否满
    41. if (ps->pos == ps->capacity)
    42. {
    43. //扩容
    44. int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//扩2倍
    45. STDataType* tmp = (STDataType*)realloc(ps->arr, newCapacity * sizeof(STDataType));
    46. if (tmp == NULL)
    47. {
    48. perror("reamlloc fail");
    49. exit(-1);
    50. }
    51. //跟新容量
    52. ps->arr = tmp;
    53. ps->capacity = newCapacity;
    54. }
    55. //入栈
    56. ps->arr[ps->pos] = x;
    57. ps->pos++;//下标++
    58. }
    59. //出栈
    60. void StackPop(ST* ps)
    61. {
    62. assert(ps);
    63. //断言栈是否为空
    64. assert(!StackEmpty(ps));
    65. --ps->pos;
    66. }
    67. //判断栈是否为空
    68. bool StackEmpty(ST* ps)
    69. {
    70. assert(ps);
    71. return ps->pos == 0;
    72. }
    73. //显示返回栈顶数据
    74. STDataType StackTop(ST* ps)
    75. {
    76. assert(ps);
    77. //断言栈是否为空
    78. assert(!StackEmpty(ps));
    79. return ps->arr[ps->pos - 1];//下标已经前移
    80. }
    81. //返回栈的长度
    82. int StackSize(ST* ps)
    83. {
    84. assert(ps);
    85. return ps->pos;
    86. }
    87. int StackSize(ST* ps);
    88. typedef struct {
    89. ST PushST;//入队列
    90. ST PopST;//出队列
    91. } MyQueue;
    92. MyQueue* myQueueCreate() {
    93. //为模拟的队列开辟空间
    94. MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    95. //初始化
    96. StackInit(&obj->PushST);
    97. StackInit(&obj->PopST);
    98. return obj;
    99. }
    100. void myQueuePush(MyQueue* obj, int x) {
    101. StackPush(&obj->PushST, x);
    102. }
    103. void PushSTTOPopST(MyQueue* obj)
    104. {
    105. //判断PopST是否为空
    106. if (StackEmpty(&obj->PopST))
    107. {
    108. while (!(StackEmpty(&obj->PushST)))
    109. {
    110. StackPush(&obj->PopST, StackTop(&obj->PushST));
    111. StackPop(&obj->PushST);
    112. }
    113. }
    114. }
    115. int myQueuePop(MyQueue* obj) {
    116. //将PuahST中的元素都倒入PopST中
    117. PushSTTOPopST(obj);
    118. int fornt = StackTop(&obj->PopST);
    119. StackPop(&obj->PopST);
    120. return fornt;
    121. }
    122. int myQueuePeek(MyQueue* obj) {
    123. //将PuahST中的元素都倒入PopST中
    124. PushSTTOPopST(obj);
    125. return StackTop(&obj->PopST);
    126. }
    127. bool myQueueEmpty(MyQueue* obj) {
    128. return StackEmpty(&obj->PushST) && StackEmpty(&obj->PopST);
    129. }
    130. void myQueueFree(MyQueue* obj) {
    131. //销毁空间
    132. StackDestroy(&obj->PushST);
    133. StackDestroy(&obj->PushST);
    134. free(obj);
    135. }

     3 设计循环队列

     对于设计循环队列来说有二种思路:

    1 用数组实现

    2 用链表实现

     

     

    对于这二种思路,我会首选思路1,为什么会这么说呢?

    因为用链表实现循环队列,首先你要malloc多份空间,而且这样你还不好判断循环队列是否已满!

    所以:我会选择用思路1来为大家解题。

    此题有个重点:那就是如何判断队列是否以满。

    因为在对于空和满来说,队列中指针fornt和back都是指向同一个位置。

    那么我们这么去解决呢?

    我们有二个思路:

    1多开辟一块空间

    2用size标记队列的长度,当size==k时就满

    下面我们用思路1来解决:

     代码转换:

    1. bool myCircularQueueIsFull(MyCircularQueue* obj) {
    2. return (obj->back + 1) % obj->n == obj->fornt;
    3. }

    完整代码:

    1. typedef struct {
    2. int* arr;
    3. int fornt;
    4. int back;
    5. int n;
    6. } MyCircularQueue;
    7. MyCircularQueue* myCircularQueueCreate(int k) {
    8. MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    9. obj->arr = (int*)malloc(sizeof(int) * (k + 1));
    10. obj->fornt = obj->back=0;
    11. obj->n = k + 1;
    12. return obj;
    13. }
    14. bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    15. return obj->fornt == obj->back;
    16. }
    17. bool myCircularQueueIsFull(MyCircularQueue* obj) {
    18. return (obj->back + 1) % obj->n == obj->fornt;
    19. }
    20. bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    21. if (myCircularQueueIsFull(obj))
    22. {
    23. return false;
    24. }
    25. obj->arr[obj->back] = value;
    26. obj->back++;
    27. //如果back指针已经指向尾,需要重新指向头
    28. obj->back %= obj->n;
    29. return true;
    30. }
    31. bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    32. if (myCircularQueueIsEmpty(obj))
    33. {
    34. return false;
    35. }
    36. obj->fornt++;
    37. //如果fornt指针已经指向尾,需要重新指向头
    38. obj->fornt %= obj->n;
    39. return true;
    40. }
    41. int myCircularQueueFront(MyCircularQueue* obj) {
    42. if (myCircularQueueIsEmpty(obj))
    43. {
    44. return -1;
    45. }
    46. return obj->arr[obj->fornt];
    47. }
    48. int myCircularQueueRear(MyCircularQueue* obj) {
    49. if (myCircularQueueIsEmpty(obj))
    50. {
    51. return -1;
    52. }
    53. else if(obj->back==0)
    54. return obj->arr[obj->n-1];
    55. else
    56. return obj->arr[obj->back-1];
    57. // return obj->arr[(obj->back -1 + obj->n) % obj->n];
    58. }
    59. void myCircularQueueFree(MyCircularQueue* obj) {
    60. free(obj->arr);
    61. free(obj);
    62. }

  • 相关阅读:
    4.20.1 深度神经网络提高放射科医生在乳腺癌筛查中的表现
    【Python】Python 发布订阅模式实现松耦合
    Bootstrap前端开发框架(简介、版本、优点、使用、布局容器、栅格系统(栅格选项参数,列嵌套,列偏移,列排序,响应式工具))
    图像识别-YOLO V8安装部署-window-CPU-Pycharm
    【无标题】QCC 308x 518x 517x增加usb voice 32k采样率
    【flask】服务端获取客户端请求的文件
    【HTML5入门指北】第二篇 网页相关的标签
    如何将pdf转word?这几个软件可以做到文档格式转换
    八、JavaScript:事件监听器
    μC/OS-II---计时器管理1(os_tmr.c)
  • 原文地址:https://blog.csdn.net/qq_61552595/article/details/126796410