当前位置:   article > 正文

C语言中的循环队列与栈、队列之间的转换实现

C语言中的循环队列与栈、队列之间的转换实现

引言

数据结构的学习中,栈(Stack)和队列(Queue)是两个非常重要的概念。它们分别遵循着后进先出(LIFO)和先进先出(FIFO)的原则。在某些情况下,我们可能需要通过栈来模拟队列,或者通过队列来模拟栈的行为。本文将详细介绍这两种数据结构,并提供相应的C语言实现代码和图解。

一、栈(Stack

栈是一种后进先出(LIFO)的数据结构,只允许在一端进行操作,这一端被称为栈顶(top)。栈的基本操作包括入栈(push)和出栈(pop)。

C语言实现栈

  1. // 支持动态增长的栈
  2. typedef int STDataType;
  3. typedef struct Stack
  4. {
  5. STDataType* _a;
  6. int _top; // 栈顶
  7. int _capacity; // 容量
  8. }Stack;
  9. // 初始化栈
  10. void StackInit(Stack* ps)
  11. {
  12. assert(ps);
  13. ps->_a = NULL;
  14. //top指向栈顶数据的下一个位置
  15. ps->_top = 0;
  16. //top指向栈顶数据
  17. //ps->_top = -1;
  18. ps->_capacity = 0;
  19. }
  20. // 入栈
  21. void StackPush(Stack* ps, STDataType data)
  22. {
  23. assert(ps);
  24. if (ps->_top == ps->_capacity)
  25. {
  26. int newcapacity = ps->_capacity == 0 ? 4 : ps->_capacity * 2;
  27. STDataType* tmp = (STDataType*)realloc(ps->_a, newcapacity * (sizeof(STDataType)));
  28. if (tmp == NULL)
  29. {
  30. perror("realloc fail");
  31. return;
  32. }
  33. ps->_a = tmp;
  34. ps->_capacity = newcapacity;
  35. }
  36. ps->_a[ps->_top] = data;
  37. ps->_top++;
  38. }
  39. // 出栈
  40. void StackPop(Stack* ps)
  41. {
  42. assert(ps);
  43. assert(ps->_top > 0);
  44. ps->_top--;
  45. }
  46. // 获取栈顶元素
  47. STDataType StackTop(Stack* ps)
  48. {
  49. assert(ps);
  50. assert(ps->_top > 0);
  51. return ps->_a[ps->_top - 1];
  52. }
  53. // 获取栈中有效元素个数
  54. int StackSize(Stack* ps)
  55. {
  56. assert(ps);
  57. return ps->_top;
  58. }
  59. // 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
  60. int StackEmpty(Stack* ps)
  61. {
  62. assert(ps);
  63. assert(ps);
  64. return ps->_top == 0;
  65. }
  66. // 销毁栈
  67. void StackDestroy(Stack* ps)
  68. {
  69. assert(ps);
  70. free(ps->_a);
  71. ps->_a = NULL;
  72. ps->_top = ps->_capacity = 0;
  73. }

栈的图解

(可以想象一个竖直的容器,新元素从顶部加入,也是从顶部取出。)

二、队列(Queue)

队列是一种先进先出(FIFO)的数据结构,只允许在两端进行操作,一端为队头(front),另一端为队尾(rear)。队列的基本操作包括入队(enqueue)和出队(dequeue)。C语言实现队列

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define MAX_SIZE 100
  4. typedef struct
  5. {
  6. int data[MAX_SIZE];
  7. int front, rear;
  8. } Queue;
  9. void initQueue(Queue *q)
  10. {
  11. q->front = q->rear = -1;
  12. }
  13. int isFull(Queue *q)
  14. {
  15. return (q->rear + 1) % MAX_SIZE == q->front;
  16. }
  17. int isEmpty(Queue *q)
  18. {
  19. return q->front == -1;
  20. }
  21. void enqueue(Queue *q, int value)
  22. {
  23. if (!isFull(q))
  24. {
  25. q->data[++q->rear] = value;
  26. }
  27. else
  28. {
  29. printf("Queue is full!\n");
  30. }
  31. }
  32. int dequeue(Queue *q)
  33. {
  34. if (!isEmpty(q))
  35. {
  36. int value = q->data[q->front++];
  37. if (q->front > q->rear) q->front = q->rear = -1; // 处理队列为空的情况
  38. return value;
  39. } else
  40. {
  41. printf("Queue is empty!\n");
  42. return -1;
  43. }
  44. }
  45. // ... 其他队列操作函数 ...

队列的图解

(可以想象一个水平的容器,新元素从尾部加入,从头部取出。)

三、循环队列

循环队列是对普通队列的一种改进,通过取模运算实现队首和队尾的循环,从而更高效地利用存储空间。相当于队列头尾相接,同时容量固定.

(代码与上面的队列实现类似,主要区别在于isFullisEmpty的判断,以及frontrear的更新方式。)

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdbool.h>
  4. #include <assert.h>
  5. typedef struct
  6. {
  7. int* a;
  8. int head; //指向头
  9. int tail; //指向尾下一个
  10. int k; //容量
  11. } MyCircularQueue;
  12. MyCircularQueue* myCircularQueueCreate(int k)
  13. {
  14. MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
  15. if (obj == NULL)
  16. {
  17. return;
  18. }
  19. //多开一个解决假溢出问题
  20. obj->a = (int*)malloc(sizeof(int)*(k + 1));
  21. obj->head = 0;
  22. obj->tail = 0;
  23. obj->k = k;
  24. return obj;
  25. }
  26. bool myCircularQueueIsEmpty(MyCircularQueue* obj)
  27. {
  28. return obj->head == obj->tail;
  29. }
  30. bool myCircularQueueIsFull(MyCircularQueue* obj)
  31. {
  32. return (obj->tail + 1) % (obj->k + 1) == obj->head;
  33. }
  34. bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
  35. {
  36. if (myCircularQueueIsFull(obj))
  37. {
  38. return false;
  39. }
  40. obj->a[obj->tail] = value;
  41. obj->tail++;
  42. obj->tail %= (obj->k + 1);
  43. return true;
  44. }
  45. bool myCircularQueueDeQueue(MyCircularQueue* obj)
  46. {
  47. if (myCircularQueueIsEmpty(obj))
  48. {
  49. return false;
  50. }
  51. ++obj->head;
  52. obj->head %= (obj->k + 1);
  53. return true;
  54. }
  55. int myCircularQueueFront(MyCircularQueue* obj)
  56. {
  57. if (myCircularQueueIsEmpty(obj))
  58. {
  59. return -1;
  60. }
  61. else
  62. {
  63. return obj->a[obj->head];
  64. }
  65. }
  66. int myCircularQueueRear(MyCircularQueue* obj)
  67. {
  68. if (myCircularQueueIsEmpty(obj))
  69. {
  70. return -1;
  71. }
  72. else
  73. {
  74. return obj->a[(obj->tail + obj->k) % (obj->k + 1)];
  75. }
  76. }
  77. void myCircularQueueFree(MyCircularQueue* obj)
  78. {
  79. free(obj->a);
  80. free(obj);
  81. }
四、栈实现队列

虽然栈是后进先出的数据结构,但我们可以通过两个栈(一个作为输入栈,一个作为输出栈)来模拟队列的先进先出特性。

代码实现

(主要涉及两个栈的push和pop操作,以及如何在适当的时候交换两个栈的角色。)

  1. // 支持动态增长的栈
  2. typedef int STDataType;
  3. typedef struct Stack
  4. {
  5. STDataType* _a;
  6. int _top; // 栈顶
  7. int _capacity; // 容量
  8. }Stack;
  9. // 初始化栈
  10. void StackInit(Stack* ps)
  11. {
  12. assert(ps);
  13. ps->_a = NULL;
  14. //top指向栈顶数据的下一个位置
  15. ps->_top = 0;
  16. //top指向栈顶数据
  17. //ps->_top = -1;
  18. ps->_capacity = 0;
  19. }
  20. // 入栈
  21. void StackPush(Stack* ps, STDataType data)
  22. {
  23. assert(ps);
  24. if (ps->_top == ps->_capacity)
  25. {
  26. int newcapacity = ps->_capacity == 0 ? 4 : ps->_capacity * 2;
  27. STDataType* tmp = (STDataType*)realloc(ps->_a, newcapacity * (sizeof(STDataType)));
  28. if (tmp == NULL)
  29. {
  30. perror("realloc fail");
  31. return;
  32. }
  33. ps->_a = tmp;
  34. ps->_capacity = newcapacity;
  35. }
  36. ps->_a[ps->_top] = data;
  37. ps->_top++;
  38. }
  39. // 出栈
  40. void StackPop(Stack* ps)
  41. {
  42. assert(ps);
  43. assert(ps->_top > 0);
  44. ps->_top--;
  45. }
  46. // 获取栈顶元素
  47. STDataType StackTop(Stack* ps)
  48. {
  49. assert(ps);
  50. assert(ps->_top > 0);
  51. return ps->_a[ps->_top - 1];
  52. }
  53. // 获取栈中有效元素个数
  54. int StackSize(Stack* ps)
  55. {
  56. assert(ps);
  57. return ps->_top;
  58. }
  59. // 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
  60. int StackEmpty(Stack* ps)
  61. {
  62. assert(ps);
  63. assert(ps);
  64. return ps->_top == 0;
  65. }
  66. // 销毁栈
  67. void StackDestroy(Stack* ps)
  68. {
  69. assert(ps);
  70. free(ps->_a);
  71. ps->_a = NULL;
  72. ps->_top = ps->_capacity = 0;
  73. }
  74. //leetcode
  75. typedef struct
  76. {
  77. Stack pushst;
  78. Stack popst;
  79. } MyQueue;
  80. MyQueue* myQueueCreate()
  81. {
  82. MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
  83. if (obj == NULL)
  84. {
  85. return;
  86. }
  87. StackInit(&(obj->popst));
  88. StackInit(&(obj->pushst));
  89. return obj;
  90. }
  91. void myQueuePush(MyQueue* obj, int x)
  92. {
  93. StackPush(&(obj->pushst), x);
  94. }
  95. int myQueuePeek(MyQueue* obj)
  96. {
  97. if (StackEmpty(&(obj->popst)))
  98. {
  99. //倒数据
  100. while (!StackEmpty(&(obj->pushst)))
  101. {
  102. int top = StackTop(&(obj->pushst));
  103. StackPush(&(obj->popst), top);
  104. StackPop(&(obj->pushst));
  105. }
  106. }
  107. return StackTop(&(obj->popst));
  108. }
  109. int myQueuePop(MyQueue* obj)
  110. {
  111. int front = myQueuePeek(obj);
  112. StackPop(&(obj->popst));
  113. return front;
  114. }
  115. bool myQueueEmpty(MyQueue* obj)
  116. {
  117. return StackEmpty(&(obj->popst)) && StackEmpty(&(obj->pushst));
  118. }
  119. void myQueueFree(MyQueue* obj)
  120. {
  121. StackDestroy(&(obj->popst));
  122. StackDestroy(&(obj->pushst));
  123. free(obj);
  124. }
五、队列实现栈

队列是先进先出的数据结构,但通过两个队列(或者一个队列和一个辅助栈)也可以模拟栈的后进先出特性。

代码实现

  1. typedef char QDataType;
  2. typedef struct QueueNode
  3. {
  4. struct QueueNode* next;
  5. QDataType val;
  6. }QNode;
  7. typedef struct Queue
  8. {
  9. QNode* phead;
  10. QNode* ptail;
  11. int size;
  12. }Queue;
  13. void QueueInit(Queue* pq)
  14. {
  15. assert(pq);
  16. pq->phead = NULL;
  17. pq->ptail = NULL;
  18. pq->size = 0;
  19. }
  20. void QueueDestroy(Queue* pq)
  21. {
  22. assert(pq);
  23. QNode* cur = pq->phead;
  24. while (cur)
  25. {
  26. QNode* next = cur->next;
  27. free(cur);
  28. cur = next;
  29. }
  30. pq->phead = pq->ptail = NULL;
  31. pq->size = 0;
  32. }
  33. // 队尾插入
  34. void QueuePush(Queue* pq, QDataType x)
  35. {
  36. assert(pq);
  37. QNode* newnode = (QNode*)malloc(sizeof(QNode));
  38. if (newnode == NULL)
  39. {
  40. perror("malloc fail");
  41. return;
  42. }
  43. newnode->next = NULL;
  44. newnode->val = x;
  45. if (pq->ptail == NULL)
  46. {
  47. pq->phead = pq->ptail = newnode;
  48. }
  49. else
  50. {
  51. pq->ptail->next = newnode;
  52. pq->ptail = newnode;
  53. }
  54. pq->size++;
  55. }
  56. // 队头删除
  57. void QueuePop(Queue* pq)
  58. {
  59. assert(pq);
  60. assert(pq->size != 0);
  61. /*QNode* next = pq->phead->next;
  62. free(pq->phead);
  63. pq->phead = next;
  64. if (pq->phead == NULL)
  65. pq->ptail = NULL;*/
  66. // 一个节点
  67. if (pq->phead->next == NULL)
  68. {
  69. free(pq->phead);
  70. pq->phead = pq->ptail = NULL;
  71. }
  72. else // 多个节点
  73. {
  74. QNode* next = pq->phead->next;
  75. free(pq->phead);
  76. pq->phead = next;
  77. }
  78. pq->size--;
  79. }
  80. QDataType QueueFront(Queue* pq)
  81. {
  82. assert(pq);
  83. assert(pq->phead);
  84. return pq->phead->val;
  85. }
  86. QDataType QueueBack(Queue* pq)
  87. {
  88. assert(pq);
  89. assert(pq->ptail);
  90. return pq->ptail->val;
  91. }
  92. int QueueSize(Queue* pq)
  93. {
  94. assert(pq);
  95. return pq->size;
  96. }
  97. bool QueueEmpty(Queue* pq)
  98. {
  99. assert(pq);
  100. return pq->size == 0;
  101. }
  102. typedef struct
  103. {
  104. Queue q1;
  105. Queue q2;
  106. } MyStack;
  107. //leetcode
  108. MyStack* myStackCreate()
  109. {
  110. MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
  111. QueueInit(&(pst->q1));
  112. QueueInit(&(pst->q2));
  113. return pst;
  114. }
  115. void myStackPush(MyStack* obj, int x)
  116. {
  117. if (!QueueEmpty(&(obj->q1)))
  118. {
  119. QueuePush(&(obj->q1), x);
  120. }
  121. else
  122. {
  123. QueuePush(&(obj->q2), x);
  124. }
  125. }
  126. int myStackPop(MyStack* obj)
  127. {
  128. //假设法
  129. Queue* empty = &(obj->q1);
  130. Queue* nonempty = &(obj->q2);
  131. if (!QueueEmpty(&(obj->q1)))
  132. {
  133. nonempty = &(obj->q1);
  134. empty = &(obj->q2);
  135. }
  136. //不为空前size-1导走,删除最后一个就是栈顶数据
  137. while (QueueSize(nonempty) > 1)
  138. {
  139. QueuePush(empty, QueueFront(nonempty));
  140. QueuePop(nonempty);
  141. }
  142. int top = QueueFront(nonempty);
  143. QueuePop(nonempty);
  144. return top;
  145. }
  146. int myStackTop(MyStack* obj)
  147. {
  148. if (!QueueEmpty(&(obj->q1)))
  149. {
  150. return QueueBack(&(obj->q1));
  151. }
  152. else
  153. {
  154. return QueueBack(&(obj->q2));
  155. }
  156. }
  157. bool myStackEmpty(MyStack* obj)
  158. {
  159. return QueueEmpty(&(obj->q1)) && QueueEmpty(&(obj->q2));
  160. }
  161. void myStackFree(MyStack* obj)
  162. {
  163. QueueDestroy(&(obj->q1));
  164. QueueDestroy(&(obj->q2));
  165. free(obj);
  166. }

分享到这里,欢迎翻阅我的文章.

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/597181
推荐阅读
相关标签
  

闽ICP备14008679号