当前位置:   article > 正文

栈&队列OJ练习题(C语言版)

栈&队列OJ练习题(C语言版)

目录

一、括号匹配问题

思路:

完整版C语言代码:  

讲解:

二、用队列实现栈

思路:

完整版C语言代码: 

讲解: 

三、用栈实现队列

思路:

完整版C语言代码:

讲解:

四、 设计循环队列

思路:

完整版C语言代码:

讲解:


如果栈和队列忘了,不妨看看小生的这两篇复习一下数据结构与算法—栈     数据结构与算法—队列

一、括号匹配问题

20. 有效的括号 - 力扣(LeetCode)

 

思路:

将左括号放入栈中,通过出栈与为入栈的符号进行比较。 

由于我们用C语言做这道题,所以代码前要加上咱们实现的的代码,同时要将数据类型STDataType改为char类型。

完整版C语言代码:  

  1. typedef char STDataType;
  2. typedef struct Stack
  3. {
  4. STDataType* a;
  5. int top;
  6. int capacity;
  7. }ST;
  8. void STInit(ST* pst)
  9. {
  10. assert(pst);
  11. pst->a = NULL;
  12. pst->top = 0;
  13. pst->capacity = 0;
  14. }
  15. void STDestroy(ST* pst)
  16. {
  17. assert(pst);
  18. free(pst->a);
  19. pst->a = NULL;
  20. pst->top = 0;
  21. pst->capacity = 0;
  22. }
  23. void STPush(ST* pst,STDataType x)
  24. {
  25. if (pst->top == pst->capacity) {
  26. int newCapacity = pst->capacity == 0 ? 4 :pst-> capacity * 2;
  27. STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType));
  28. if (tmp == NULL) {
  29. perror("realloc fail");
  30. return;
  31. }
  32. pst->a = tmp;
  33. pst->capacity = newCapacity;
  34. }
  35. pst->a[pst->top] = x;
  36. pst->top++;
  37. }
  38. bool STEmpty(ST* pst)
  39. {
  40. assert(pst);
  41. return pst->top == 0;
  42. }
  43. void STPop(ST* pst)
  44. {
  45. assert(pst);
  46. assert(!STEmpty(pst));
  47. pst->top--;
  48. }
  49. STDataType STTop(ST* pst)
  50. {
  51. assert(pst);
  52. assert(!STEmpty(pst));
  53. return pst->a[pst->top - 1];
  54. }
  55. int STSize(ST* pst)
  56. {
  57. assert(pst);
  58. return pst->top;
  59. }
  60. //------以下为OJ提供-------
  61. bool isValid(char* s) {
  62. ST st;
  63. STInit(&st);
  64. while (*s) {
  65. if (*s == '(' || *s == '[' || *s == '{') {
  66. STPush(&st, *s);
  67. }
  68. else {
  69. if (STEmpty(&st)) {
  70. STDestroy(&st);
  71. return false;
  72. }
  73. char top = STTop(&st);
  74. STPop(&st);
  75. if ((top != '(' && *s == ')') ||
  76. (top != '{' && *s == '}') ||
  77. (top != '[' && *s == ']')) {
  78. STDestroy(&st);
  79. return false;
  80. }
  81. }
  82. s++;
  83. }
  84. bool ret = STEmpty(&st);
  85. STDestroy(&st);
  86. return ret;
  87. }

讲解:

isValid函数:

  • 创建栈结构体ST变量 st,然后进行初始化。
  • 以*s为循环进行条件
  • 首先,创建一个名为 st 的 ST 结构体实例,并使用 STInit 初始化它。

  • 然后,遍历输入字符串 s 中的每个字符。
  • 对于每个字符,如果是左括号 '(','[','{' ,则将其推入栈中。
  • 如果是右括号 ')',']','}' ,则执行以下操作:

检查栈是否为空,如果为空,表示没有对应的左括号,则销毁栈,返回 false

否则,弹出栈顶元素,将其与当前右括号进行匹配。如果不匹配,则销毁栈,返回 false

  • 最后,遍历完整个字符串后,检查栈是否为空。如果栈为空,表示所有括号都成功匹配,返回 true,否则返回 false
  • 最后,调用 STDestroy 销毁栈,并返回最终的匹配结果。

二、用队列实现栈

225. 用队列实现栈 - 力扣(LeetCode)

 

思路:

 准备两个队列,第一个队列依次出队到只剩一个数据时停止,将已出队的数据依次入队到第二个队列,将第一个队列仅剩的一个数据出队即实现了栈的出栈。入栈时哪个队列不为空则在哪个队列入队。

由于我们用C语言做这道题,所以代码前要加上咱们实现的队列的代码。

完整版C语言代码: 

  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* 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. QNode* next = cur->next;
  26. free(cur);
  27. cur = next;
  28. }
  29. pq->phead = pq->ptail = NULL;
  30. pq->size = 0;
  31. }
  32. void QueuePush(Queue* pq, QDataType x)
  33. {
  34. assert(pq);
  35. QNode* newnode = (QNode*)malloc(sizeof(QNode));
  36. if (newnode == NULL) {
  37. perror("mallloc fail\n");
  38. return;
  39. }
  40. newnode->data = x;
  41. newnode->next = NULL;
  42. if (pq->ptail == NULL) {
  43. assert(pq->phead == NULL);
  44. pq->phead = pq->ptail = newnode;
  45. }
  46. else {
  47. pq->ptail->next = newnode;
  48. pq->ptail = newnode;
  49. }
  50. pq->size++;
  51. }
  52. bool QueueEmpty(Queue* pq)
  53. {
  54. assert(pq);
  55. return pq->size == 0;
  56. }
  57. void QueuePop(Queue* pq)
  58. {
  59. assert(pq);
  60. assert(!QueueEmpty(pq));
  61. if (pq->phead->next == NULL) {
  62. free(pq->phead);
  63. pq->phead = pq->ptail = NULL;
  64. }
  65. else {
  66. QNode* next = pq->phead->next;
  67. free(pq->phead);
  68. pq->phead = next;
  69. }
  70. pq->size--;
  71. }
  72. QDataType QueueFront(Queue* pq)
  73. {
  74. assert(pq);
  75. assert(!QueueEmpty(pq));
  76. return pq->phead->data;
  77. }
  78. QDataType QueueBack(Queue* pq)
  79. {
  80. assert(pq);
  81. assert(!QueueEmpty(pq));
  82. return pq->ptail->data;
  83. }
  84. int QueueSize(Queue* pq)
  85. {
  86. assert(pq);
  87. return pq->size;
  88. }
  89. //------以下为OJ提供-------
  90. typedef struct {
  91. Queue q1;
  92. Queue q2;
  93. } MyStack;
  94. MyStack* myStackCreate() {
  95. MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
  96. if (obj == NULL) {
  97. perror("malloc fail");
  98. return NULL;
  99. }
  100. QueueInit(&obj->q1);
  101. QueueInit(&obj->q2);
  102. return obj;
  103. }
  104. void myStackPush(MyStack* obj, int x) {
  105. if (!QueueEmpty(&obj->q1)) {
  106. QueuePush(&obj->q1, x);
  107. }
  108. else {
  109. QueuePush(&obj->q2, x);
  110. }
  111. }
  112. int myStackPop(MyStack* obj) {
  113. Queue* pEmptyQ = &obj->q1;
  114. Queue* pNonEmptyQ = &obj->q2;
  115. if (!QueueEmpty(&obj->q1)) {
  116. pEmptyQ = &obj->q2;
  117. pNonEmptyQ = &obj->q1;
  118. }
  119. while (QueueSize(pNonEmptyQ) > 1) {
  120. QueuePush(pEmptyQ, QueueFront(pNonEmptyQ));
  121. QueuePop(pNonEmptyQ);
  122. }
  123. int top = QueueFront(pNonEmptyQ);
  124. QueuePop(pNonEmptyQ);
  125. return top;
  126. }
  127. int myStackTop(MyStack* obj) {
  128. if (!QueueEmpty(&obj->q1)) {
  129. return QueueBack(&obj->q1);
  130. }
  131. else {
  132. return QueueBack(&obj->q2);
  133. }
  134. }
  135. bool myStackEmpty(MyStack* obj) {
  136. return QueueEmpty(&obj->q1) &&
  137. QueueEmpty(&obj->q2);
  138. }
  139. void myStackFree(MyStack* obj) {
  140. QueueDestroy(&obj->q1);
  141. QueueDestroy(&obj->q2);
  142. free(obj);
  143. }

讲解: 

 1、

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

首先在匿名结构体MyStack中设置两个成员 q1、q2,他们的类型为结构体Queue。

2、

  1. MyStack* myStackCreate() {
  2. MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
  3. if (obj == NULL) {
  4. perror("malloc fail");
  5. return NULL;
  6. }
  7. QueueInit(&obj->q1);
  8. QueueInit(&obj->q2);
  9. return obj;
  10. }

myStackCreate中首先创建结构体 MyStack 指针 obj,并为其开辟空间,开辟失败则打印错误信息,然后对 obj 的两个成员 (队列) 进行初始化。

3、

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

myStackPush中首先判断哪个队列不为空,对不为空的队列进行入队(入栈)。

4、

  1. int myStackPop(MyStack* obj) {
  2. Queue* pEmptyQ = &obj->q1;
  3. Queue* pNonEmptyQ = &obj->q2;
  4. if (!QueueEmpty(&obj->q1)) {
  5. pEmptyQ = &obj->q2;
  6. pNonEmptyQ = &obj->q1;
  7. }
  8. while (QueueSize(pNonEmptyQ) > 1) {
  9. QueuePush(pEmptyQ, QueueFront(pNonEmptyQ));
  10. QueuePop(pNonEmptyQ);
  11. }
  12. int top = QueueFront(pNonEmptyQ);
  13. QueuePop(pNonEmptyQ);
  14. return top;
  15. }
  • myStackPop中首先要找到为“空”和“不为空”的队列,假设队列q1为空,q2不为空,通过QueueEmpty判断如果q1为空则假设不变,否则二者互换。
  • 然后将不为空的队列的数据依次入队到为空的队列,入队结束后将不为空的队列进行出队,进行下一次循环,直到不为空的队列只剩一个元素停止循环。
  • 调用QueueFront函数获取队头节点赋值给变量top,将不为空队列仅剩的数据出队。
  • 返回top。

5、

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

myStackTop函数找出不为空的队列,对不为空的队列调用QueueBack返回栈顶元素。

6、

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

myStackEmpty调用QueueEmpty判断两个队列是否为空即为判断栈是否为空。

7、

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

myStackFree调用 QueueDestroy释放两个队列的内存空间,最后释放栈 obj 的内存空间。

三、用栈实现队列

232. 用栈实现队列 - 力扣(LeetCode)

思路:

一个栈用于入队,一个栈用于出队。出队栈不为空则从入队栈依次出栈,然后入栈到出队栈,这时原本入队栈的数据在出队栈中直接出栈,即可实现队列的先进先出,再次入队时数据进入入队栈,等待出队栈为空时再将数据倒过来。

 

 由于我们用C语言做这道题,所以代码前要加上咱们实现的的代码。

完整版C语言代码:

  1. typedef int STDataType;
  2. typedef struct Stack
  3. {
  4. STDataType* a;
  5. int top;
  6. int capacity;
  7. }ST;
  8. void STInit(ST* pst)
  9. {
  10. assert(pst);
  11. pst->a = NULL;
  12. pst->top = 0;
  13. pst->capacity = 0;
  14. }
  15. void STDestroy(ST* pst)
  16. {
  17. assert(pst);
  18. free(pst->a);
  19. pst->a = NULL;
  20. pst->top = 0;
  21. pst->capacity = 0;
  22. }
  23. void STPush(ST* pst, STDataType x)
  24. {
  25. if (pst->top == pst->capacity) {
  26. int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
  27. STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType));
  28. if (tmp == NULL) {
  29. perror("realloc fail");
  30. return;
  31. }
  32. pst->a = tmp;
  33. pst->capacity = newCapacity;
  34. }
  35. pst->a[pst->top] = x;
  36. pst->top++;
  37. }
  38. bool STEmpty(ST* pst)
  39. {
  40. assert(pst);
  41. return pst->top == 0;
  42. }
  43. void STPop(ST* pst)
  44. {
  45. assert(pst);
  46. assert(!STEmpty(pst));
  47. pst->top--;
  48. }
  49. STDataType STTop(ST* pst)
  50. {
  51. assert(pst);
  52. assert(!STEmpty(pst));
  53. return pst->a[pst->top - 1];
  54. }
  55. int STSize(ST* pst)
  56. {
  57. assert(pst);
  58. return pst->top;
  59. }
  60. //------以下为OJ提供-------
  61. typedef struct {
  62. ST pushst;
  63. ST popst;
  64. } MyQueue;
  65. MyQueue* myQueueCreate() {
  66. MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
  67. if (obj == NULL) {
  68. perror("malloc fail");
  69. return 0;
  70. }
  71. STInit(&obj->pushst);
  72. STInit(&obj->popst);
  73. return obj;
  74. }
  75. void myQueuePush(MyQueue* obj, int x) {
  76. STPush(&obj->pushst, x);
  77. }
  78. int myQueuePop(MyQueue* obj) {
  79. int front = myQueuePeek(obj);
  80. STPop(&obj->popst);
  81. return front;
  82. }
  83. int myQueuePeek(MyQueue* obj) {
  84. if (STEmpty(&obj->popst)) {
  85. while (!STEmpty(&obj->pushst)) {
  86. STPush(&obj->popst, STTop(&obj->pushst));
  87. STPop(&obj->pushst);
  88. }
  89. }
  90. return STTop(&obj->popst);
  91. }
  92. bool myQueueEmpty(MyQueue* obj) {
  93. return STEmpty(&obj->pushst) && STEmpty(&obj->popst);
  94. }
  95. void myQueueFree(MyQueue* obj) {
  96. STDestroy(&obj->pushst);
  97. STDestroy(&obj->popst);
  98. free(obj);
  99. }

讲解:

1、

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

在MyQueue结构体中创建两个栈 pushst 和 popst。

2、

  1. MyQueue* myQueueCreate() {
  2. MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
  3. if (obj == NULL) {
  4. perror("malloc fail");
  5. return 0;
  6. }
  7. STInit(&obj->pushst);
  8. STInit(&obj->popst);
  9. return obj;
  10. }

创建一个 MyQueue 类型的队列 obj 。然后通过 malloc 申请内存,如果申请失败则调用perror打印错误信息,结束函数,然后分别初始化 pushst 和 popst 两个栈,返回队列obj。

 3、

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

将元素 x 入队。直接调用 STPush 函数将元素 x 压入 pushst 栈。

 4、

  1. int myQueuePop(MyQueue* obj) {
  2. int front = myQueuePeek(obj);
  3. STPop(&obj->popst);
  4. return front;
  5. }

这个函数用于将队首元素出队,并返回其值。首先调用 myQueuePeek 函数获取队首元素的值,然后调用 STPop 函数将元素从 popst 栈中弹出。

5、 

  1. int myQueuePeek(MyQueue* obj) {
  2. if (STEmpty(&obj->popst)) {
  3. while (!STEmpty(&obj->pushst)) {
  4. STPush(&obj->popst, STTop(&obj->pushst));
  5. STPop(&obj->pushst);
  6. }
  7. }
  8. return STTop(&obj->popst);
  9. }

这个函数用于获取队首元素的值。首先判断 popst 栈是否为空,如果为空则将 pushst 栈中的所有元素依次弹出并压入 popst 栈,最后通过 STTop 函数获取 popst 栈顶元素的值。

6、

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

 这个函数用于判断队列是否为空。只有当 pushst 和 popst 两个栈都为空时,队列才为空。

7、 

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

这个函数用于释放 MyQueue 类型队列所占用的内存空间。

首先调用 STDestroy 函数销毁 pushst 和 popst 两个栈,然后调用 free 函数释放 obj 所占用的内存空间。

四、 设计循环队列

622. 设计循环队列

 

 思路:

选择数组作为循环队列,为了避免队列为空和队列为满时 front 和 rear 相同的情况,将数组的容量设置为比题中要求的队列长度大一(即实际容量为k+1)。

 

完整版C语言代码:

  1. typedef struct {
  2. int front;
  3. int rear;
  4. int k;
  5. int* a;
  6. } MyCircularQueue;
  7. MyCircularQueue* myCircularQueueCreate(int k) {
  8. MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
  9. obj->a = (int*)malloc((k + 1) * sizeof(int));
  10. obj->k = k;
  11. obj->front = obj->rear = 0;
  12. return obj;
  13. }
  14. bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
  15. return obj->front == obj->rear;
  16. }
  17. bool myCircularQueueIsFull(MyCircularQueue* obj) {
  18. return (obj->rear + 1) % (obj->k + 1) == obj->front;
  19. }
  20. bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
  21. if (myCircularQueueIsFull(obj)) {
  22. return false;
  23. }
  24. obj->a[obj->rear] = value;
  25. obj->rear++;
  26. obj->rear %= (obj->k + 1);
  27. return true;
  28. }
  29. bool myCircularQueueDeQueue(MyCircularQueue* obj) {
  30. if (myCircularQueueIsEmpty(obj)) {
  31. return false;
  32. }
  33. obj->front++;
  34. obj->front %= (obj->k + 1);
  35. return true;
  36. }
  37. int myCircularQueueFront(MyCircularQueue* obj) {
  38. if (myCircularQueueIsEmpty(obj)) {
  39. return -1;
  40. }
  41. return obj->a[obj->front];
  42. }
  43. int myCircularQueueRear(MyCircularQueue* obj) {
  44. if (myCircularQueueIsEmpty(obj)) {
  45. return -1;
  46. }
  47. return obj->a[(obj->rear + obj->k) % (obj->k + 1)];
  48. }
  49. void myCircularQueueFree(MyCircularQueue* obj) {
  50. free(obj->a);
  51. free(obj);
  52. }

讲解:

1、

  1. typedef struct {
  2. int front;
  3. int rear;
  4. int k;
  5. int* a;
  6. } MyCircularQueue;

定义MyCircularQueue结构体,front指向队列第一个元素,rear指向队列最后一个元素的下一个位置,k为队列容量,指针a用于动态分配数组存储队列元素。

2、 

  1. MyCircularQueue* myCircularQueueCreate(int k) {
  2. MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
  3. obj->a = (int*)malloc((k + 1) * sizeof(int));
  4. obj->k = k;
  5. obj->front = obj->rear = 0;
  6. return obj;
  7. }

对队列obj开辟空间,为数组a分配k+1个整型元素大小的空间,多出来的一个空间用于区分空队列和满队列,将k的值存储在队列obj中,初始化 front 和 rear 为 0。

这里将检查队列是否为空或已满的函数从后面移动到这里,方便后续函数能正常调用。 

3、

  1. bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
  2. return obj->front == obj->rear;
  3. }

如果front与rear重合,则队列为空。

4、

  1. bool myCircularQueueIsFull(MyCircularQueue* obj) {
  2. return (obj->rear + 1) % (obj->k + 1) == obj->front;
  3. }

通过 (obj->rear + 1) % (obj->k + 1) 计算下一个元素将要插入的位置,如果这个位置和 front 相同,说明队列已满。

5、

  1. bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
  2. if (myCircularQueueIsFull(obj)) {
  3. return false;
  4. }
  5. obj->a[obj->rear] = value;
  6. obj->rear++;
  7. obj->rear %= (obj->k + 1);
  8. return true;
  9. }

首先检查队列是否已满。

  • 如果满了,返回 false;不满则将数据放入数组的rear位置,然后rear向后移动一位。
  • 如果rear移动到最后一个元素的后一项位置,则通过 obj->rear %= (obj->k + 1); 更新rear的位置。

6、 

  1. bool myCircularQueueDeQueue(MyCircularQueue* obj) {
  2. if (myCircularQueueIsEmpty(obj)) {
  3. return false;
  4. }
  5. obj->front++;
  6. obj->front %= (obj->k + 1);
  7. return true;
  8. }
  • 首先检查队列是否为空。如果为空,返回 false,
  • 如果不空,更新 front 的值,表示已经移除了一个元素,返回 true。

7、 

  1. int myCircularQueueFront(MyCircularQueue* obj) {
  2. if (myCircularQueueIsEmpty(obj)) {
  3. return -1;
  4. }
  5. return obj->a[obj->front];
  6. }
  • 如果队列为空,返回 -1。
  • 如果不空,返回 front 指向的元素。

8、 

  1. int myCircularQueueRear(MyCircularQueue* obj) {
  2. if (myCircularQueueIsEmpty(obj)) {
  3. return -1;
  4. }
  5. return obj->a[(obj->rear + obj->k) % (obj->k + 1)];
  6. }
  • 如果队列为空,返回 -1。
  • 如果不空,返回 rear 指向的前一个元素。

 9、

  1. void myCircularQueueFree(MyCircularQueue* obj) {
  2. free(obj->a);
  3. free(obj);
  4. }

释放队列数组 a 和队列结构体的内存空间。

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

闽ICP备14008679号