• 数据结构-栈和队列力扣题


    目录

    有效的括号

    用队列实现栈

     用栈实现队列

     设计循环队列


    有效的括号

    题目链接:力扣(LeetCode)

    思路: 这道题可以用栈来解决,先让字符串中的左括号' ( ',' [ ',' { '入栈,s指向字符串下一个字符,如果该字符也是左括号,那就继续入栈,如果是右括号,那就让其与栈顶元素相匹配(每次都要弹出栈顶元素),匹配上了,继续循环,匹配不上就返回false,注意在每次返回false之前都要销毁栈。

    还要考虑极端情况,如果全是左括号,我们要在代码最后进行判空,不为空,返回false,同时,这次判空也能解决前面几对都匹配上,只有最后一个左括号没匹配上的问题(例如:"()[]{}{")。

    如果全是右括号,说明整个过程中没有入栈元素,此时判空,如果为空返回false,同时,这次判空也能解决前面几对都匹配上,只有最后一个右括号没匹配上的问题(例如:"()[]{}}")。

    如果用C语言来解题的话,栈需要自己写。

    代码如下:

    1. typedef int STDatatype;
    2. typedef struct Stack
    3. {
    4. STDatatype* a;
    5. int top;
    6. int capacity;
    7. }ST;
    8. //初始化栈
    9. void STInit(ST* pst)
    10. {
    11. assert(pst);
    12. pst->a = NULL;
    13. pst->top = 0;
    14. pst->capacity = 0;
    15. }
    16. //入栈
    17. void STPush(ST* pst, STDatatype x)
    18. {
    19. //开辟空间
    20. if (pst->top == pst->capacity)
    21. {
    22. int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
    23. STDatatype* tmp = (STDatatype*)realloc(pst->a, sizeof(STDatatype) * newcapacity);
    24. if (tmp == NULL)
    25. {
    26. perror("realloc fail");
    27. return;
    28. }
    29. pst->a = tmp;
    30. pst->capacity = newcapacity;
    31. }
    32. //插入
    33. pst->a[pst->top] = x;
    34. pst->top++;
    35. }
    36. //判空函数
    37. bool STEmpty(ST* pst)
    38. {
    39. assert(pst);
    40. return pst->top == 0;
    41. }
    42. //出栈
    43. void STPop(ST* pst)
    44. {
    45. assert(pst);
    46. assert(!STEmpty(pst));
    47. pst->top--;
    48. }
    49. //获取栈顶元素
    50. STDatatype STTop(ST* pst)
    51. {
    52. assert(pst);
    53. assert(!STEmpty(pst));
    54. return pst->a[pst->top - 1];
    55. }
    56. //获取栈中有效数据的个数
    57. int STSize(ST* pst)
    58. {
    59. assert(pst);
    60. return pst->top;
    61. }
    62. //销毁栈
    63. void STDestory(ST* pst)
    64. {
    65. assert(pst);
    66. free(pst->a);
    67. pst->a = NULL;
    68. pst->top = pst->capacity = 0;
    69. }
    70. bool isValid(char* s) {
    71. ST st;
    72. STInit(&st);
    73. while(*s)
    74. {
    75. if(*s=='('||*s=='['||*s=='{')
    76. {
    77. STPush(&st,*s);
    78. }
    79. else
    80. {
    81. if(STEmpty(&st))
    82. {
    83. STDestory(&st);
    84. return false;
    85. }
    86. char top=STTop(&st);
    87. STPop(&st);
    88. if((top!='('&&*s==')')
    89. ||(top!='['&&*s==']')
    90. ||(top!='{'&&*s=='}'))
    91. {
    92. STDestory(&st);
    93. return false;
    94. }
    95. }
    96. ++s;
    97. }
    98. bool ret=STEmpty(&st);
    99. STDestory(&st);
    100. return ret;
    101. }

    用队列实现栈

    题目链接:力扣(LeetCode)

     思路:队列是先入先出,栈是先入后出,要用队列实现栈,我们可以定义两个栈q1和q2,当它们都为空时,随便选一个存入数据,假设q1中有数据1 2 3 4,我们可以把q1中的1 2 3 push进q2中,然后把q1中的4 pop出去,接着把q2中的1 2 push进q1,然后把q2中的3 pop出去,这样循环在q1和q2中倒数据,就实现了4 3 2 1依次出栈,即先入后出。

    当我们在出栈的同时,想要入栈,就把数据push进有数据的队列即可。

    想要用C语言做这道题,队列的实现代码也要自己写。

    注意,我们下列代码是结构体的三层嵌套,所以销毁时要先销毁q1和q2,再销毁obj,如果只销毁obj,由于我们的队列q1和q2中分别有两个头尾指针还有节点,会造成内存泄漏的问题。

    它们的关系图如下:

    代码如下:

    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. //初始化队列
    14. void QueueInit(Queue* pq)
    15. {
    16. pq->phead = NULL;
    17. pq->ptail = NULL;
    18. pq->size = 0;
    19. }
    20. //队尾入队列
    21. void QueuePush(Queue* pq, QDatatype x)
    22. {
    23. assert(pq);
    24. QNode* newnode = (QNode*)malloc(sizeof(QNode));
    25. if (newnode == NULL)
    26. {
    27. perror("malloc fail");
    28. return;
    29. }
    30. newnode->data = x;
    31. newnode->next = NULL;
    32. if (pq->ptail == NULL)
    33. {
    34. assert(pq->phead == NULL);
    35. pq->phead = pq->ptail=newnode;
    36. }
    37. else
    38. {
    39. pq->ptail->next = newnode;
    40. pq->ptail = newnode;
    41. }
    42. pq->size++;
    43. }
    44. //判空函数
    45. bool QueueEmpty(Queue* pq)
    46. {
    47. assert(pq);
    48. return pq->size ==0 ;
    49. }
    50. //队头出队列
    51. void QueuePop(Queue* pq)
    52. {
    53. assert(pq);
    54. assert(!QueueEmpty(pq));
    55. //一个节点
    56. //多个节点
    57. if (pq->phead->next == NULL)
    58. {
    59. free(pq->phead);
    60. pq->phead = pq->ptail= NULL;
    61. }
    62. else
    63. {
    64. QNode* next = pq->phead->next;
    65. free(pq->phead);
    66. pq->phead = next;
    67. }
    68. pq->size--;
    69. }
    70. //获取队列头部元素
    71. QDatatype QueueFront(Queue* pq)
    72. {
    73. assert(pq);
    74. assert(!QueueEmpty(pq));
    75. return pq->phead->data;
    76. }
    77. //获取队列尾部元素
    78. QDatatype QueueBack(Queue* pq)
    79. {
    80. assert(pq);
    81. assert(!QueueEmpty(pq));
    82. return pq->ptail->data;
    83. }
    84. //获取队列中有效元素个数
    85. int Queuesize(Queue* pq)
    86. {
    87. assert(pq);
    88. return pq->size;
    89. }
    90. //销毁队列
    91. void DestoryQueue(Queue* pq)
    92. {
    93. assert(pq);
    94. while (pq->phead)
    95. {
    96. QNode* next = pq->phead->next;
    97. free(pq->phead);
    98. pq->phead = next;
    99. }
    100. pq->phead = pq->ptail = NULL;
    101. pq->size = 0;
    102. }
    103. typedef struct {
    104. Queue q1;
    105. Queue q2;
    106. } MyStack;
    107. MyStack* myStackCreate() {
    108. MyStack* obj=(MyStack*)malloc(sizeof(MyStack));
    109. if(obj==NULL)
    110. {
    111. perror("malloc fail");
    112. return NULL;
    113. }
    114. QueueInit(&obj->q1);
    115. QueueInit(&obj->q2);
    116. return obj;
    117. }
    118. void myStackPush(MyStack* obj, int x) {
    119. if(!QueueEmpty(&obj->q1))
    120. {
    121. QueuePush(&obj->q1,x);
    122. }
    123. else
    124. {
    125. QueuePush(&obj->q2,x);
    126. }
    127. }
    128. int myStackPop(MyStack* obj) {
    129. Queue* pemptyq=&obj->q1;
    130. Queue* pnoemptyq=&obj->q2;
    131. if(!QueueEmpty(&obj->q1))
    132. {
    133. pemptyq=&obj->q2;
    134. pnoemptyq=&obj->q1;
    135. }
    136. while(Queuesize(pnoemptyq)>1)
    137. {
    138. QueuePush(pemptyq,QueueFront(pnoemptyq));
    139. QueuePop(pnoemptyq);
    140. }
    141. int top=QueueFront(pnoemptyq);
    142. QueuePop(pnoemptyq);
    143. return top;
    144. }
    145. int myStackTop(MyStack* obj) {
    146. if(!QueueEmpty(&obj->q1))
    147. return QueueBack(&obj->q1);
    148. else
    149. return QueueBack(&obj->q2);
    150. }
    151. bool myStackEmpty(MyStack* obj) {
    152. assert(obj);
    153. return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
    154. }
    155. void myStackFree(MyStack* obj) {
    156. DestoryQueue(&obj->q1);
    157. DestoryQueue(&obj->q2);
    158. free(obj);
    159. }

     用栈实现队列

    题目链接:力扣(LeetCode)

    思路:这道题用上道题的思路也能实现,但是过于复杂。

    简单思路:我们定义两个栈pushstpopst,栈中数据遵循先入后出的原则,如果在pushstpush进去1 2 3 4,那他从栈顶到栈底依次是 4 3 2 1 ,但是如果我们把pushst中的数据再pushpopst中,那popst中从栈顶到栈底依次是 1 2 3 4,此时我们只要将popst中的数据按照栈本身先入后出的原则pop出去,就是1 2 3 4,这样就实现了先入先出。如下图:

    当我们在出队列的同时,想要入队列,要先等popst中的数据出完才行,所以当popst为空,pushst不为空时,才能把pushst中的数据往popstpush

    代码如下:

    1. typedef int STDatatype;
    2. typedef struct Stack
    3. {
    4. STDatatype* a;
    5. int top;
    6. int capacity;
    7. }ST;
    8. //初始化栈
    9. void STInit(ST* pst)
    10. {
    11. assert(pst);
    12. pst->a = NULL;
    13. pst->top = 0;
    14. pst->capacity = 0;
    15. }
    16. //入栈
    17. void STPush(ST* pst, STDatatype x)
    18. {
    19. //开辟空间
    20. if (pst->top == pst->capacity)
    21. {
    22. int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
    23. STDatatype* tmp = (STDatatype*)realloc(pst->a, sizeof(STDatatype) * newcapacity);
    24. if (tmp == NULL)
    25. {
    26. perror("realloc fail");
    27. return;
    28. }
    29. pst->a = tmp;
    30. pst->capacity = newcapacity;
    31. }
    32. //插入
    33. pst->a[pst->top] = x;
    34. pst->top++;
    35. }
    36. //判空函数
    37. bool STEmpty(ST* pst)
    38. {
    39. assert(pst);
    40. return pst->top == 0;
    41. }
    42. //出栈
    43. void STPop(ST* pst)
    44. {
    45. assert(pst);
    46. assert(!STEmpty(pst));
    47. pst->top--;
    48. }
    49. //获取栈顶元素
    50. STDatatype STTop(ST* pst)
    51. {
    52. assert(pst);
    53. assert(!STEmpty(pst));
    54. return pst->a[pst->top - 1];
    55. }
    56. //获取栈中有效数据的个数
    57. int STSize(ST* pst)
    58. {
    59. assert(pst);
    60. return pst->top;
    61. }
    62. //销毁栈
    63. void STDestory(ST* pst)
    64. {
    65. assert(pst);
    66. free(pst->a);
    67. pst->a = NULL;
    68. pst->top = pst->capacity = 0;
    69. }
    70. typedef struct {
    71. ST pushst;
    72. ST popst;
    73. } MyQueue;
    74. MyQueue* myQueueCreate() {
    75. MyQueue*obj=(MyQueue*)malloc(sizeof(MyQueue));
    76. if(obj==NULL)
    77. {
    78. perror("malloc fail\n");
    79. return NULL;
    80. }
    81. STInit(&obj->pushst);
    82. STInit(&obj->popst);
    83. return obj;
    84. }
    85. void myQueuePush(MyQueue* obj, int x) {
    86. STPush(&obj->pushst,x);
    87. }
    88. int myQueuePop(MyQueue* obj) {
    89. int front= myQueuePeek(obj);
    90. STPop(&obj->popst);
    91. return front;
    92. }
    93. int myQueuePeek(MyQueue* obj) {
    94. if(STEmpty(&obj->popst))
    95. {
    96. while(!STEmpty(&obj->pushst))
    97. {
    98. STPush(&obj->popst,STTop(&obj->pushst));
    99. STPop(&obj->pushst);
    100. }
    101. }
    102. return STTop(&obj->popst);
    103. }
    104. bool myQueueEmpty(MyQueue* obj) {
    105. assert(obj);
    106. return STEmpty(&obj->pushst)&&STEmpty(&obj->popst);
    107. }
    108. void myQueueFree(MyQueue* obj) {
    109. STDestory(&obj->pushst);
    110. STDestory(&obj->popst);
    111. free(obj);
    112. }

     设计循环队列

    题目链接:力扣(LeetCode)

    思路: 本题用数组队列和链表队列都能实现,在这里我们使用数组队列,首先,要设计一个循环队列,我们就要知道队列什么时候满,什么时候空,空很容易判断,当front=rear时就为空,问题是当我们循环一圈以后,队列已经满了,但此时front也等于rear,所以为了不发生混淆,我们在开辟空间时多开辟一块,假设要存7个数据就开辟8个空间:

    此时当rear+1==front时就为满。但这只是上图为了形象展示,实际上在数组中,每存一个数,rear++,但是数组首尾并没有相连,不能用rear+1==front判断是否满了,我们可以用下标rear,当(rear+1)%(k+1)==front时就说明队列满了

    而要在队列中插入数据,每次插入之后下标rear++,但是当队列满了之后,rear就是数组中最后一个下标,这时如果我们在队头出了两个数据,想再往队列里插数据,就要让rear回到开始的位置,所以每次rear++后,让rear=rear%(k+1),此时再插入,就形成了一个完美的循环,同理,删除数据也一样,每次删完都让front=front%(k+1)

    obj->a[(obj->rear+obj->k)%(obj->k+1)]这段代码是为了返回队尾元素。

    代码如下:

    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(sizeof(int)*(k+1));
    10. obj->front=obj->rear=0;
    11. obj->k=k;
    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. obj->a[obj->rear]=value;
    24. obj->rear++;
    25. obj->rear=(obj->rear)%(obj->k+1);
    26. return true;
    27. }
    28. bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    29. if(myCircularQueueIsEmpty(obj))
    30. return false;
    31. obj->front++;
    32. obj->front=(obj->front)%(obj->k+1);
    33. return true;
    34. }
    35. int myCircularQueueFront(MyCircularQueue* obj) {
    36. if(myCircularQueueIsEmpty(obj))
    37. return -1;
    38. else
    39. return obj->a[obj->front];
    40. }
    41. int myCircularQueueRear(MyCircularQueue* obj) {
    42. if(myCircularQueueIsEmpty(obj))
    43. return -1;
    44. else
    45. return obj->a[(obj->rear+obj->k)%(obj->k+1)];
    46. }
    47. void myCircularQueueFree(MyCircularQueue* obj) {
    48. free(obj->a);
    49. free(obj);
    50. }

    栈与队列的内容到这里就结束了,下节开始学习堆与二叉树

    未完待续。。。 

  • 相关阅读:
    【数据结构初阶】四、线性表里的链表(带头+双向+循环 链表)
    Android Qcom Sensor架构学习
    golang 基础-golang里面的读写锁实现与核心原理分析
    RK3588 linux内核中断之下半部 tasklet(三)
    Ubuntu 软件安装方法(入门必看)
    学习笔记-数据结构-树与二叉树(2024-04-23)
    Pytest系列-数据驱动@pytest.mark.parametrize(7)
    [SpringBoot] AOP-AspectJ 切面技术
    [Java面试]Spring总结以及在面试中的一些问题.
    【ROS2要素】xml、GDF、URDF的关系
  • 原文地址:https://blog.csdn.net/syh163/article/details/134307083