• 【C语言】栈和队列的相互实现


    目录

    用队列实现栈

    代码实现

    完整代码

    用栈实现队列

     代码实现

    完整代码


    用队列实现栈

    力扣链接用队列实现栈

    这个题目,使用队列模拟实现栈,我们是使用C语言来实现,由于C语言没有相应的库所以我们要先手写一个队列出来,在此之前我们还要对队列和栈的性质有所了解 ,可以参考我之前写的文章——队列的模拟实现)和(栈的模拟实现

    方法两个队列

    为了满足栈的特性,即最后入栈的元素最先出栈,在使用队列实现栈时,应满足队列前端的元素是最后入栈的元素。所以我们可以使用两个队列实现栈的操作,其中一个队列用来存储栈内的元素,另一个队列用来倒数据。

    入栈操作把数据入队到其中一个队列中,另一个队列保持为空队列。

    出栈操作:将存储了栈内元素的队列倒到另一个空的队列中,当倒了只剩下一个数据时停止,将这个数据出队就达到了出栈的效果。

      

    代码实现

     创建两个队列

    1. typedef struct
    2. {
    3. Queue q1;
    4. Queue q2;
    5. } MyStack;

    初始化 

    1. MyStack* myStackCreate() {
    2. MyStack* obj=(MyStack*)malloc(sizeof(MyStack));
    3. QueueInit(&obj->q1);
    4. QueueInit(&obj->q2);
    5. return obj;
    6. }

     首先看一下这样写行不行?

    这样写当然是不行的,因为它是带返回值的,所以我们要返回我们创建的地址,但是st是局部变量,出了这个函数就销毁了,那你接受到的只能是野指针。

    所以这里只能用静态的或者malloc动态的,出了这个函数也不会被销毁,但是malloc更好,那我们就用malloc的,然后初始化这两个队列 就行了。

    入栈

    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. int myStackPop(MyStack* obj) {
    2. Queue* emptyQ=&obj->q1;
    3. Queue* nonEmptyQ=&obj->q2;
    4. if(!QueueEmpty(&obj->q1))
    5. {
    6. emptyQ=&obj->q2;
    7. nonEmptyQ=&obj->q1;
    8. }
    9. while(QueueSize(nonEmptyQ)>1)
    10. {
    11. QueuePush(emptyQ,QueueFront(nonEmptyQ));
    12. QueuePop(nonEmptyQ);
    13. }
    14. int top=QueueFront(nonEmptyQ);
    15. QueuePop(nonEmptyQ);
    16. return top;
    17. }

     这里就需要倒数据了,但是我们不知道哪个为空,哪个不为空,我们可以用假设法。先假设一个为空 ,一个不为空,再来一个if语句判断一下,确定哪个为空,哪个不为空。然后将非空队列的数据倒入空的队列中去,当非空对列倒的只剩下一个数据时就停止,最后pop掉这个数据。

     获取栈顶元素

    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. bool myStackEmpty(MyStack* obj) {
    2. return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
    3. }

    注意这里是&&而不是|| ,我们是用两个队列来模拟栈,只有当两个队列都为空时,栈才是空。

    销毁栈

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

     我们不仅要销毁这两个队列,还要free掉队列中指针指向的链表。

    完整代码

    1. typedef int QDataType;
    2. typedef struct QueueNode
    3. {
    4. struct QueueNode* next;
    5. QDataType data;
    6. }QNode;
    7. typedef struct Queue
    8. {
    9. int size;
    10. QNode* head;
    11. QNode* tail;
    12. }Queue;
    13. //初始化队列
    14. void QueueInit(Queue* pq);
    15. //销毁队列
    16. void QueueDestroy(Queue* pq);
    17. //对尾入队列
    18. void QueuePush(Queue* pq, QDataType x);
    19. //对头出队列
    20. void QueuePop(Queue* pq);
    21. //获取对列头部元素
    22. QDataType QueueFront(Queue* pq);
    23. //获取队列队尾元素
    24. QDataType QueueBack(Queue* pq);
    25. //判空
    26. bool QueueEmpty(Queue* pq);
    27. //获取队列中有效元素的个数
    28. int QueueSize(Queue* pq);
    29. void QueueInit(Queue* pq)
    30. {
    31. assert(pq);
    32. pq->size = 0;
    33. pq->head = pq->tail = NULL;
    34. }
    35. void QueueDestroy(Queue* pq)
    36. {
    37. assert(pq);
    38. QNode* cur = pq->head;
    39. while (cur)
    40. {
    41. QNode* next = cur->next;
    42. free(cur);
    43. cur = next;
    44. }
    45. pq->head = pq->tail = NULL;
    46. }
    47. void QueuePush(Queue* pq, QDataType x)
    48. {
    49. assert(pq);
    50. QNode* newnode = (QNode*)malloc(sizeof(QNode));
    51. if (newnode == NULL)
    52. {
    53. printf("malloc fail\n");
    54. exit(-1);
    55. }
    56. newnode->data = x;
    57. newnode->next = NULL;
    58. if (pq->tail == NULL)
    59. {
    60. pq->head = pq->tail = newnode;
    61. }
    62. else
    63. {
    64. pq->tail->next = newnode;
    65. pq->tail = newnode;
    66. }
    67. pq->size++;
    68. }
    69. void QueuePop(Queue* pq)
    70. {
    71. assert(pq);
    72. assert(!QueueEmpty(pq));
    73. //1.一个节点
    74. if (pq->head->next == NULL)
    75. {
    76. free(pq->head);
    77. pq->head = pq->tail = NULL;//避免野指针问题
    78. }
    79. //2.多个节点
    80. else
    81. {
    82. QNode* next = pq->head->next;
    83. free(pq->head);
    84. pq->head = next;
    85. }
    86. pq->size--;
    87. }
    88. QDataType QueueFront(Queue* pq)
    89. {
    90. assert(pq);
    91. assert(!QueueEmpty(pq));
    92. return pq->head->data;
    93. }
    94. QDataType QueueBack(Queue* pq)
    95. {
    96. assert(pq);
    97. assert(!QueueEmpty(pq));
    98. return pq->tail->data;
    99. }
    100. bool QueueEmpty(Queue* pq)
    101. {
    102. assert(pq);
    103. return pq->head == NULL;
    104. }
    105. int QueueSize(Queue* pq)
    106. {
    107. assert(pq);
    108. /*int size = 0;
    109. QNode* cur = pq->head;
    110. while (cur)
    111. {
    112. size++;
    113. cur = cur->next;
    114. }*/
    115. return pq->size;
    116. }
    117. typedef struct
    118. {
    119. Queue q1;
    120. Queue q2;
    121. } MyStack;
    122. MyStack* myStackCreate() {
    123. MyStack* obj=(MyStack*)malloc(sizeof(MyStack));
    124. QueueInit(&obj->q1);
    125. QueueInit(&obj->q2);
    126. return obj;
    127. }
    128. void myStackPush(MyStack* obj, int x) {
    129. if(!QueueEmpty(&obj->q1))
    130. {
    131. QueuePush(&obj->q1,x);
    132. }
    133. else
    134. {
    135. QueuePush(&obj->q2,x);
    136. }
    137. }
    138. int myStackPop(MyStack* obj) {
    139. Queue* emptyQ=&obj->q1;
    140. Queue* nonEmptyQ=&obj->q2;
    141. if(!QueueEmpty(&obj->q1))
    142. {
    143. emptyQ=&obj->q2;
    144. nonEmptyQ=&obj->q1;
    145. }
    146. while(QueueSize(nonEmptyQ)>1)
    147. {
    148. QueuePush(emptyQ,QueueFront(nonEmptyQ));
    149. QueuePop(nonEmptyQ);
    150. }
    151. int top=QueueFront(nonEmptyQ);
    152. QueuePop(nonEmptyQ);
    153. return top;
    154. }
    155. int myStackTop(MyStack* obj) {
    156. if(!QueueEmpty(&obj->q1))
    157. {
    158. return QueueBack(&obj->q1);
    159. }
    160. else
    161. {
    162. return QueueBack(&obj->q2);
    163. }
    164. }
    165. bool myStackEmpty(MyStack* obj) {
    166. return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
    167. }
    168. void myStackFree(MyStack* obj) {
    169. QueueDestroy(&obj->q1);
    170. QueueDestroy(&obj->q2);
    171. free(obj);
    172. }

    用栈实现队列

    力扣链接用栈实现队列

    这个题目是用栈实现队列,我们依然使用C语言来写,C语言没有相应的库,所以我们还是要先手写一个栈才能实现题目中要求的函数接口。

    方法两个栈

    一个队列是先进先出,一个栈是先进后出,新进的数据肯定是在栈底。我们可以这样做,指定一个栈专门进数据,指定另外一个栈专门出数据。

    入队操作向push栈中入数据。

     出对操作将push栈中的数据全部倒入pop栈中,pop栈中数据的顺序刚好与push栈中的数据顺序相反,正好满足队列的性质,最后在push栈的栈顶出数据就行了。

     

     代码实现

    创建两个栈

    1. typedef struct {
    2. ST pushst;
    3. ST popst;
    4. } MyQueue;

     指定一个栈专门进数据,指定另外一个栈专门出数据。

    初始化

    1. MyQueue* myQueueCreate() {
    2. MyQueue*obj=(MyQueue*)malloc(sizeof(MyQueue));
    3. StackInit(&obj->pushst);
    4. StackInit(&obj->popst);
    5. return obj;
    6. }

    销毁队列

    1. void myQueueFree(MyQueue* obj) {
    2. StackDestroy(&obj->popst);
    3. StackDestroy(&obj->pushst);
    4. free(obj);
    5. }

    初始化和销毁队列的方法和上面题目的方法一致,就不多讲了。

    入队

    1. void myQueuePush(MyQueue* obj, int x) {
    2. StackPush(&obj->pushst,x);
    3. }

     入对只需要push进栈就行啦。

    出队

    1. int myQueuePop(MyQueue* obj) {
    2. if(StackEmpty(&obj->popst))
    3. {
    4. //如果pop栈为空,则把push栈的数据倒过来
    5. while(!StackEmpty(&obj->pushst))
    6. {
    7. StackPush(&obj->popst,StackTop(&obj->pushst));
    8. StackPop(&obj->pushst);
    9. }
    10. }
    11. int front=StackTop(&obj->popst);
    12. StackPop(&obj->popst);
    13. return front;
    14. }

     首先要判断一下popst栈为不为空,如果为空,则把push栈的数据倒过来,不为空就直接在pop栈出数据。

    取对头元素

    1. int myQueuePeek(MyQueue* obj) {
    2. if(StackEmpty(&obj->popst))
    3. {
    4. //如果pop栈为空,则把push栈的数据倒过来
    5. while(!StackEmpty(&obj->pushst))
    6. {
    7. StackPush(&obj->popst,StackTop(&obj->pushst));
    8. StackPop(&obj->pushst);
    9. }
    10. }
    11. return StackTop(&obj->popst);
    12. }

     这个就简单了,只需要取pop栈的栈顶的数据返回就可以了。

    判空

    1. bool myQueueEmpty(MyQueue* obj) {
    2. return StackEmpty(&obj->popst)&&StackEmpty(&obj->pushst);
    3. }

    两个栈等于一个队列,所以两个栈都需要判空。 和上面的题目一样。

    完整代码

    1. typedef int STDataType;
    2. typedef struct Stack
    3. {
    4. STDataType* a;
    5. int top;
    6. int capacity;
    7. }ST;
    8. //初始化栈
    9. void StackInit(ST* ps);
    10. //销毁栈
    11. void StackDestroy(ST* ps);
    12. //进栈
    13. void StackPush(ST* ps, STDataType x);
    14. //出栈
    15. void StackPop(ST* ps);
    16. //获取栈顶元素
    17. STDataType StackTop(ST* ps);
    18. //判空
    19. bool StackEmpty(ST* ps);
    20. //栈的元素个数
    21. int StackSize(ST* ps);
    22. void StackInit(ST* ps)
    23. {
    24. assert(ps);
    25. ps->a = NULL;
    26. ps->top = 0;
    27. ps->capacity = 0;
    28. }
    29. void StackDestroy(ST* ps)
    30. {
    31. assert(ps);
    32. free(ps->a);
    33. ps->a = NULL;
    34. ps->top = ps->capacity = 0;
    35. }
    36. void StackPush(ST* ps, STDataType x)
    37. {
    38. assert(ps);
    39. if (ps->top == ps->capacity)
    40. {
    41. int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
    42. STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType)* newcapacity);
    43. if (tmp == NULL)
    44. {
    45. printf("realloc fail\n");
    46. exit(-1);
    47. }
    48. ps->a = tmp;
    49. ps->capacity = newcapacity;
    50. }
    51. ps->a[ps->top] = x;
    52. ps->top++;
    53. }
    54. void StackPop(ST* ps)
    55. {
    56. assert(ps);
    57. assert(!StackEmpty(ps));
    58. ps->top--;
    59. }
    60. STDataType StackTop(ST* ps)
    61. {
    62. assert(ps);
    63. assert(!StackEmpty(ps));
    64. return ps->a[ps->top - 1];
    65. }
    66. bool StackEmpty(ST* ps)
    67. {
    68. assert(ps);
    69. return ps->top == 0;
    70. }
    71. int StackSize(ST* ps)
    72. {
    73. assert(ps);
    74. return ps->top;
    75. }
    76. typedef struct {
    77. ST pushst;
    78. ST popst;
    79. } MyQueue;
    80. MyQueue* myQueueCreate() {
    81. MyQueue*obj=(MyQueue*)malloc(sizeof(MyQueue));
    82. StackInit(&obj->pushst);
    83. StackInit(&obj->popst);
    84. return obj;
    85. }
    86. void myQueuePush(MyQueue* obj, int x) {
    87. StackPush(&obj->pushst,x);
    88. }
    89. int myQueuePop(MyQueue* obj) {
    90. if(StackEmpty(&obj->popst))
    91. {
    92. //如果pop栈为空,则把push栈的数据倒过来
    93. while(!StackEmpty(&obj->pushst))
    94. {
    95. StackPush(&obj->popst,StackTop(&obj->pushst));
    96. StackPop(&obj->pushst);
    97. }
    98. }
    99. int front=StackTop(&obj->popst);
    100. StackPop(&obj->popst);
    101. return front;
    102. }
    103. int myQueuePeek(MyQueue* obj) {
    104. if(StackEmpty(&obj->popst))
    105. {
    106. //如果pop栈为空,则把push栈的数据倒过来
    107. while(!StackEmpty(&obj->pushst))
    108. {
    109. StackPush(&obj->popst,StackTop(&obj->pushst));
    110. StackPop(&obj->pushst);
    111. }
    112. }
    113. return StackTop(&obj->popst);
    114. }
    115. bool myQueueEmpty(MyQueue* obj) {
    116. return StackEmpty(&obj->popst)&&StackEmpty(&obj->pushst);
    117. }
    118. void myQueueFree(MyQueue* obj) {
    119. StackDestroy(&obj->popst);
    120. StackDestroy(&obj->pushst);
    121. free(obj);
    122. }

    总结:这两个题目是很相似的,你会写其中一个,那么另一个也不是什么难事。

  • 相关阅读:
    vscode Markdown使用
    MyCat2搭建读写分离
    Linux常用的命令和一些基础知识
    为什么程序员会秃头?盘点程序员糟心的几大因素
    PicGo+Gitee+Typora搭建云图床
    【Java】基础练习 --- Stream练习
    【CUDA编程】CUDA内存模型
    AIGC——ComfyUI 安装与基础使用
    BE节点经常挂掉:[IO_ERROR]failed to list /proc/27349/fd/: No such file or directory
    数据中台基础
  • 原文地址:https://blog.csdn.net/m0_62537611/article/details/125523833