当前位置:   article > 正文

数据结构之队列详解(包含例题)_队列数据结构题目

队列数据结构题目

一、队列的概念

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

二、模拟实现顺序队列

我们可以用单链表模拟实现顺序队列。

队列采用的FIFO(first in first out),新元素(等待进入队列的元素)总是被插入到链表的尾部(对应单链表的尾插),而读取的时候总是从链表的头部开始读取。每次读取一个元素,释放一个元素(对应单链表的头删)。

对应的接口

注意又提供一种避免使用二级指针的方法,创建一个结构体变量,里面存储结点,当我们想要改变结构体里面的值,我们就用一级指针即可。

  1. typedef int QDataType;
  2. typedef struct QueueNode
  3. {
  4. //用单链表模拟实现队列
  5. struct QueueNode* next;
  6. QDataType data;
  7. }QNode;
  8. //新的避免二级指针的结构体
  9. typedef struct Queue
  10. {
  11. QNode* head;
  12. QNode* tail;
  13. int sz;
  14. }Que;
  15. void QueueInit(Que* pq);
  16. void QueueDestory(Que* pq);
  17. void QueuePush(Que* pq, QDataType x);
  18. void QueeuPop(Que* pq);
  19. QDataType QueueFront(Que* pq);
  20. QDataType QueueBack(Que* pq);
  21. bool QueueEmpty(Que* pq);
  22. int QueueSize(Que* pq);

队列的初始化:

  1. void QueueInit(Que* pq)
  2. {
  3. assert(pq);
  4. pq->sz = 0;
  5. pq->head = pq->tail = NULL;
  6. }

队列的销毁

注意free过后,也要指向空

  1. void QueueDestroy(Que* pq)
  2. {
  3. assert(pq);
  4. while (pq->sz > 0)
  5. {
  6. QNode* cur = pq->head->next;
  7. free(pq->head);
  8. pq->head = cur;
  9. pq->sz--;
  10. }
  11. pq->tail = pq->head = NULL;
  12. }

队列的插入数据

也就是单链表的尾插,同时也要注意当队列为空时的特殊情况。

  1. void QueuePush(Que* pq,QDataType x)
  2. {
  3. //类似于尾插
  4. assert(pq);
  5. QNode* newnode = (QNode*)malloc(sizeof(QNode));
  6. if (newnode == NULL)
  7. {
  8. perror(malloc);
  9. exit(-1);
  10. }
  11. newnode->data = x;
  12. newnode->next = NULL;
  13. if (pq->head == NULL)
  14. {
  15. pq->head = pq->tail = newnode;
  16. pq->sz++;
  17. }
  18. else
  19. {
  20. pq->sz++;
  21. pq->tail->next = newnode;
  22. pq->tail = newnode;
  23. }
  24. }

队列的删除数据

也就是单链表的头删,同时也要注意只剩下一个结点删除后,尾结点指向空的情况

  1. void QueeuPop(Que* pq)
  2. {
  3. assert(pq);
  4. assert(pq->sz > 0);
  5. //头删
  6. //单独判断只剩下一个结点,头删后tail是野指针的情况
  7. if (pq->head->next == NULL)
  8. {
  9. free(pq->head);
  10. pq->head = pq->tail = NULL;
  11. pq->sz--;
  12. }
  13. else
  14. {
  15. QNode* cur = pq->head;
  16. pq->head = pq->head->next;
  17. free(cur);
  18. pq->sz--;
  19. }
  20. }

返回队列头数据

  1. QDataType QueueFront(Que* pq)
  2. {
  3. assert(pq);
  4. //assert(pq->head);
  5. assert(!QueueEmpty(pq));
  6. return pq->head->data;
  7. }

返回队列尾数据

  1. QDataType QueueBack(Que* pq)
  2. {
  3. assert(pq);
  4. assert(!QueueEmpty(pq));
  5. return pq->tail->data;
  6. }

判断队列是否为空

  1. bool QueueEmpty(Que* pq)
  2. {
  3. assert(pq);
  4. return pq->head == NULL;
  5. }

返回队列的数据个数

  1. int QueueSize(Que* pq)
  2. {
  3. assert(pq);
  4. //assert(pq->head);
  5. return pq->sz;
  6. }

三、模拟实现循环队列

622. 设计循环队列 - 力扣(LeetCode)

这实际上是把队列空间想象成一个环形空间,环形空间中的存储单元循环使用,用这种方法管理的队列也就称为循环队列。

注意本题结构较为复杂,必须要画图进行解决,这样就容易考虑到特殊情况,不容易出错。

本题用数组实现较为简单,如果用单链表实现,那么rear尾结点的前一个不好寻找。

那数组如何实现循环呢?

数组实现循环并不像单链表那样有一个next指针指向头结点,如果已经走向尾部,可以直接让头部的值等于尾部想要的值。

  1. //如何用数组实现循环?
  2. typedef struct {
  3. int* a;
  4. int front;
  5. int rear;
  6. int num;
  7. } MyCircularQueue;
  8. MyCircularQueue* myCircularQueueCreate(int k) {
  9. MyCircularQueue* cur = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
  10. //用k+1个数组空间,便于判断空和满的情况。
  11. cur->a = (int*)malloc(sizeof(int)*(k+1));
  12. cur->front = 0;
  13. cur->rear = 0;
  14. cur->num = k;
  15. return cur;
  16. }
  17. bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
  18. if(obj->front == obj->rear)
  19. return true;
  20. else
  21. return false;
  22. }
  23. bool myCircularQueueIsFull(MyCircularQueue* obj) {
  24. //两种情况都要考虑到!
  25. if(obj->front-obj->rear == 1 || obj->rear-obj->front == obj->num)
  26. return true;
  27. else
  28. return false;
  29. }
  30. bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
  31. //先判断是否已经满
  32. if(myCircularQueueIsFull(obj) == true)
  33. return false;
  34. //假设rear在队列的尾部
  35. if(obj->rear == obj->num)
  36. {
  37. obj->a[obj->rear] = value;
  38. obj->rear = 0;
  39. }
  40. else
  41. {
  42. obj->a[obj->rear] = value;
  43. obj->rear++;
  44. }
  45. //obj->a[obj->rear] = value;
  46. //obj->rear++;
  47. //obj->rear %= (obj->num+1);
  48. return true;
  49. }
  50. bool myCircularQueueDeQueue(MyCircularQueue* obj) {
  51. //先判断是否已经空了
  52. if(myCircularQueueIsEmpty(obj) == true)
  53. {
  54. return false;
  55. }
  56. //假设front在队列的尾部
  57. if(obj->front == obj->num)
  58. obj->front = 0;
  59. else
  60. obj->front++;
  61. //++obj->front;
  62. //obj->front %= (obj->num+1);
  63. return true;
  64. }
  65. int myCircularQueueFront(MyCircularQueue* obj) {
  66. if(myCircularQueueIsEmpty(obj) == true)
  67. return -1;
  68. else
  69. return obj->a[obj->front];
  70. }
  71. int myCircularQueueRear(MyCircularQueue* obj) {
  72. //注意队尾的rear比数据提前一位数,所以是rear-1
  73. //但要考虑rear-1的情况
  74. if(myCircularQueueIsEmpty(obj) == true)
  75. return -1;
  76. if(obj->rear == 0)
  77. {
  78. //需要再创建一个临时变量,不能改变rear的值
  79. int tmp = obj->num;
  80. return obj->a[tmp];
  81. }
  82. // else
  83. // return obj->a[(obj->rear+obj->num)%(obj->num+1)];
  84. return obj->a[obj->rear-1];
  85. }
  86. void myCircularQueueFree(MyCircularQueue* obj) {
  87. free(obj->a);
  88. free(obj);
  89. }

四、用队列实现栈

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

本题要求用两个队列实现栈,两个队列我们就可以互相倒数据,来满足题目对栈的需求

思路:

入队列:

入不为空的队列

出队列:

利用队列的性质将前n-1个数据放入另一个空的队列中,删除剩下一个数据,这样就完成栈的pop操作

代码:

  1. typedef struct {
  2. Que q1;
  3. Que q2;
  4. } MyStack;
  5. MyStack* myStackCreate() {
  6. MyStack* cur = (MyStack*)malloc(sizeof(MyStack));
  7. //不能忘记初始化
  8. QueueInit(&cur->q1);
  9. QueueInit(&cur->q2);
  10. return cur;
  11. }
  12. void myStackPush(MyStack* obj, int x) {
  13. //push到不为空的的队列中
  14. if(!QueueEmpty(&obj->q1))
  15. {
  16. QueuePush(&obj->q1,x);
  17. }
  18. else
  19. {
  20. QueuePush(&obj->q2,x);
  21. }
  22. }
  23. int myStackPop(MyStack* obj) {
  24. //先假设q1不为空,q2为空
  25. Que* empty = &obj->q1;
  26. Que* nonEmpty = &obj->q2;
  27. if(!QueueEmpty(&obj->q1))
  28. {
  29. //如果假设失败,相反
  30. empty = &obj->q2;
  31. nonEmpty = &obj->q1;
  32. }
  33. while(QueueSize(nonEmpty)>1)
  34. {
  35. //开始用函数进行捯数据
  36. //从前往后的顺序是根据队列pop的顺序定的
  37. QueuePush(empty,QueueFront(nonEmpty));
  38. QueuePop(nonEmpty);
  39. }
  40. int top = QueueBack(nonEmpty);
  41. QueuePop(nonEmpty);
  42. return top;
  43. }
  44. int myStackTop(MyStack* obj) {
  45. Que* empty = &obj->q1;
  46. Que* nonEmpty = &obj->q2;
  47. if(!QueueEmpty(&obj->q1))
  48. {
  49. //如果假设失败,相反
  50. empty = &obj->q2;
  51. nonEmpty = &obj->q1;
  52. }
  53. return QueueBack(nonEmpty);
  54. }
  55. bool myStackEmpty(MyStack* obj) {
  56. //判断两个队列
  57. return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
  58. }
  59. void myStackFree(MyStack* obj) {
  60. //先对两个队列中的链表进行free
  61. QueueDestroy(&obj->q1);
  62. QueueDestroy(&obj->q2);
  63. free(obj);
  64. }

五、用栈实现队列

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

题目描述:

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

思路:

本题与上一题用队列实现栈有所差别,可以直接区分push栈和pop栈,如果pop栈为空,就将push栈全部捯到pop栈

代码:

  1. typedef struct
  2. {
  3. ST push;
  4. ST pop;
  5. } MyQueue;
  6. MyQueue* myQueueCreate() {
  7. MyQueue* cur = (MyQueue*)malloc(sizeof(MyQueue));
  8. SLInit(&cur->push);
  9. SLInit(&cur->pop);
  10. return cur;
  11. }
  12. void myQueuePush(MyQueue* obj, int x) {
  13. STPush(&obj->push,x);
  14. }
  15. int myQueuePop(MyQueue* obj) {
  16. int ret = myQueuePeek(obj);
  17. STPop(&obj->pop);
  18. return ret;
  19. }
  20. int myQueuePeek(MyQueue* obj) {
  21. //出栈只能从后往前出
  22. //如果pop栈为空,就将push栈全部捯到pop栈!
  23. if(STEmpty(&obj->pop))
  24. {
  25. while(!STEmpty(&obj->push))
  26. {
  27. STPush(&obj->pop,STTop(&obj->push));
  28. STPop(&obj->push);
  29. }
  30. }
  31. int ret = STTop(&obj->pop);
  32. return ret;
  33. }
  34. bool myQueueEmpty(MyQueue* obj) {
  35. //用函数求解
  36. return STEmpty(&obj->push) && STEmpty(&obj->pop);
  37. }
  38. void myQueueFree(MyQueue* obj) {
  39. SLDestroy(&obj->pop);
  40. SLDestroy(&obj->push);
  41. free(obj);
  42. }

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

闽ICP备14008679号