当前位置:   article > 正文

数据结构之队(循环队列)的基本操作和实现_循环队列的基本操作实现

循环队列的基本操作实现

引言:这篇文章的末尾有完整的实现代码,前面还是先进行分步实现,即我们探讨一下为什么要这样做,以及我们应该怎么样一步一步的实现循环队列。

目录

一、队列的概念

二、队的基本操作

三、对于队的操作,了解若干个规则

四、对队列的基本操作进行实现

(1)、队的初始化

(2)、判断队是否为空

(3)、求队列的长度

(4)、入队操作

(5)、出队操作

(6)、求队首元素

(7)、主函数

(8)、运行结果

 (9)、完整代码

总结


一、队列的概念

       我们可以把队列理解为食堂的排队买饭,我们只能在队尾进行排队(入队操作),然后队头的同学买完饭走了(出队操作)。所以对于队的理解就很清楚了,队就是一个只允许在队头进行出队操作,在队尾进行入队操作。即队是一个先进先出的表。(FIFO)

二、队的基本操作

(1)、队的初始化

(2)、判断队是否为空

(3)、求队列的长度

(4)、入队操作

(5)、出队操作

(6)、求队首元素

三、对于队的操作,了解若干个规则

(1)、我们首先用front和rear来标记当前队列的队首的前一个位置和队尾元素。

(2)、判断对空,那就是front和rear都标记为同一个位置。

(3)、理解这段话:那我们如何判断队满,假如说我们让这个队列一直进行入队操作,那么我们是否可以说当rear标记的位置为Maxsize-1(因为数组下标是从0开始的,Maxsize-1代表最后一个位置)时,队列就满了呢?当然不可以这样,因为我们的队首可以进行出队操作,当一直出队直到标记位为rear的标记位时,这时队列并不是队满的状态,刚好是队空。所以我们要想一个办法改变这种情况。由此引出来循环队列,我们可以把这个队设置成循环队列,这样的话就可以一直转圈的入队和出队。那我们如何判断队满呢?式子((rear+1)%Maxsize==front),若成立则说明队满。我们可以分析一下为什么这样因为front是标记队首元素的前一个,rear是指向队尾元素,(rear+1)%Masize的意思是防止rear指向最后一个位置(Maxsize-1),当它再加1的时候,就是Maxsize了,已经超过了数组的最大下标,而如果我们再对Maxsize取余的话呢,当rear+1变为Maxsize之后再对Maxsize取余就变为了0,又回到了队列的首位置,所以我们这样做是有必要的。(rear+1)%Maxsize==front避免了rear会超出对大范围,当rear的下一个为front的时候,队就满了,因为我们是空出来了一个位置将front指向它,即front指向队首元素的前一个位置,这个位置并不存放东西。(rear+1)%Maxsize或者是(front+1)%Maxsize他们%Maxsize这个操作都是为了将当rear或者是front+1之后指向Maisize这个位置时,把它转换为0。

四、对队列的基本操作进行实现

首先声明一个队列结构体

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define Maxsize 5
  4. //顺序队列的实现
  5. //重新定义数据类型,typedef在这里的意思就是重新定义它后面的东西的别名
  6. typedef int ElemType;//这句话的意思就是定义int的别名为ElemType来代替int
  7. //声明一个结构体
  8. typedef struct Queue
  9. {
  10. ElemType data[Maxsize];//队列能存多少元素
  11. int front,rear; //front指向队列的前一个元素,rear指向队列的最后一个元素,即队尾
  12. }SqQueue; //重新定义结构体的名字为SqQueue

(1)、队的初始化

  1. //先进行初始化操作
  2. void Init(SqQueue *s)
  3. {
  4. s->front=s->rear=0; //将队首和队尾标记队列相同的位置
  5. }

(2)、判断队是否为空

  1. //判断队列是否为空
  2. int Empty(SqQueue s)
  3. {
  4. if(s.front==s.rear) //因为我们在初始化的时候将它们两个相等了,所以判空直接判断
  5. return 1; //为空返回真
  6. else
  7. return 0; //不为空返回假,程序中除了0全为真
  8. }

(3)、求队列的长度

求队列的长度,我们首先判断队列是否为空,如果不为空,判断rear是否大于front,若rear大于front直接相减即可,若rear小于front,相减之后为负数,再加上一个Maxsize即可,如果相减之后为正数,那么我们可以加上一个Maxsize再取余Maxsize即可,这样的话,不管rear是否发育front,我们都可以用(s.rear-s.front+Maxsize)%Maxsize来表示

  1. //求队列的长度
  2. int Length(SqQueue s)
  3. {
  4. //先判断队列是否为空
  5. if(Empty(s)) //意思是如果队列为空则返回1,那么if括号里面的意思是不等于0的话执行里面的东西
  6. {
  7. return 0;
  8. }
  9. return (s.rear-s.front+Maxsize)%Maxsize;
  10. }

(4)、入队操作

  1. //入队操作
  2. void Add(SqQueue *s,ElemType x)//将x入队
  3. {
  4. //首先判断队列是否已满
  5. if(s->front==(s->rear+1)%Maxsize) //队列中留出一个空位置让front指向它,那么当rear+1等于front的话我们就说队满了
  6. {
  7. printf("当前队列已满,不能将值为:%d的元素入队\n\n",x);
  8. return;
  9. }
  10. else
  11. {
  12. s->data[(s->rear+1)%Maxsize]=x;//在rear的下一个位置存入元素x
  13. s->rear=(s->rear+1)%Maxsize; //把rear的位置往后移一位
  14. }
  15. }

(5)、出队操作

  1. //出队操作
  2. void Dele(SqQueue *s,ElemType *e) //用e来保存出队的元素
  3. {
  4. if(Empty(*s))
  5. {
  6. printf("当前队列为空,操作失败\n\n");
  7. return;
  8. }
  9. else
  10. {
  11. *e=s->data[(s->front+1)%Maxsize];//用e来保存出队的这个元素
  12. s->front=(s->front+1)%Maxsize; //出队之后front往后移动一位
  13. }
  14. }

(6)、求队首元素

  1. //读取队首元素
  2. ElemType Get(SqQueue s)
  3. {
  4. if(Empty(s)) //意思是如果队列为空则返回1,那么if括号里面的意思是不等于0的话执行里面的东西
  5. {
  6. printf("队首元素不存在,队列为空\n\n");
  7. return 0;
  8. }
  9. return s.data[(s.front+1)%Maxsize];//返回队首元素,这样做的目的是防止front当前的位置在Maxsize这个位置
  10. }

(7)、主函数

  1. int main()
  2. {
  3. SqQueue s;//定义一个队,名称s;这里也可以定义一个队指针,用这个指针来代替这个表s,修改一下函数中的参数就行。只是实现方式不同,结果相同
  4. //进行初始化
  5. Init(&s);
  6. ElemType e=0;
  7. int x;
  8. printf("先将队列初始化之后的头标记为:%d 尾标记为:%d\n\n",s.front,s.rear);
  9. printf("队列的大小为:%d\n\n",Maxsize);
  10. //来五次入队操作
  11. Add(&s,8);
  12. Add(&s,5);
  13. Add(&s,4);
  14. Add(&s,0);
  15. Add(&s,7);
  16. //看一下当前队的长度
  17. x=Length(s);
  18. if(x)
  19. {
  20. printf("操作完成之后,当前队列的长度为:%d\n\n",Length(s));
  21. }
  22. //读取队首元素
  23. x=Get(s);
  24. if(x) //如果x不为0,执行里面的东西
  25. {
  26. printf("当前队列中的队首元素为:%d\n\n",x);
  27. }
  28. //出队操作
  29. Dele(&s,&e);
  30. Dele(&s,&e);
  31. Dele(&s,&e);
  32. //读取队首元素
  33. x=Get(s);
  34. if(!(x==0&&e==0)) //如果x和e不为0,执行里面的东西
  35. {
  36. printf("出队操作之后,刚刚出队的元素为:%d,当前队首元素为:%d\n\n",e,x);
  37. }
  38. return 0;
  39. }

(8)、运行结果

 (9)、完整代码

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define Maxsize 5
  4. //顺序队列的实现
  5. //重新定义数据类型,typedef在这里的意思就是重新定义它后面的东西的别名
  6. typedef int ElemType;//这句话的意思就是定义int的别名为ElemType来代替int
  7. //声明一个结构体
  8. typedef struct Queue
  9. {
  10. ElemType data[Maxsize];//队列能存多少元素
  11. int front,rear; //front指向队列的前一个元素,rear指向队列的最后一个元素,即队尾
  12. }SqQueue; //重新定义结构体的名字为SqQueue
  13. //先进行初始化操作
  14. void Init(SqQueue *s)
  15. {
  16. s->front=s->rear=0; //将队首和队尾标记队列相同的位置
  17. }
  18. //判断队列是否为空
  19. int Empty(SqQueue s)
  20. {
  21. if(s.front==s.rear) //因为我们在初始化的时候将它们两个相等了,所以判空直接判断
  22. return 1; //为空返回真
  23. else
  24. return 0; //不为空返回假,程序中除了0全为真
  25. }
  26. //求队列的长度
  27. int Length(SqQueue s)
  28. {
  29. //先判断队列是否为空
  30. if(Empty(s)) //意思是如果队列为空则返回1,那么if括号里面的意思是不等于0的话执行里面的东西
  31. {
  32. return 0;
  33. }
  34. return (s.rear-s.front+Maxsize)%Maxsize;
  35. }
  36. //读取队首元素
  37. ElemType Get(SqQueue s)
  38. {
  39. if(Empty(s)) //意思是如果队列为空则返回1,那么if括号里面的意思是不等于0的话执行里面的东西
  40. {
  41. printf("队首元素不存在,队列为空\n\n");
  42. return 0;
  43. }
  44. return s.data[(s.front+1)%Maxsize];//返回队首元素,这样做的目的是防止front当前的位置在Maxsize这个位置
  45. }
  46. //入队操作
  47. void Add(SqQueue *s,ElemType x)//将x入队
  48. {
  49. //首先判断队列是否已满
  50. if(s->front==(s->rear+1)%Maxsize) //对列中留出一个空位置让front指向它,那么当rear+1等于front的话我们就说队满了
  51. {
  52. printf("当前队列已满,不能将值为:%d的元素入队\n\n",x);
  53. return;
  54. }
  55. else
  56. {
  57. s->data[(s->rear+1)%Maxsize]=x;//在rear的下一个位置存入元素x
  58. s->rear=(s->rear+1)%Maxsize; //把rear的位置往后移一位
  59. }
  60. }
  61. //出队操作
  62. void Dele(SqQueue *s,ElemType *e) //用e来保存出队的元素
  63. {
  64. if(Empty(*s))
  65. {
  66. printf("当前队列为空,操作失败\n\n");
  67. return;
  68. }
  69. else
  70. {
  71. *e=s->data[(s->front+1)%Maxsize];
  72. s->front=(s->front+1)%Maxsize;
  73. }
  74. }
  75. int main()
  76. {
  77. SqQueue s;//定义一个队,名称s;这里也可以定义一个队指针,用这个指针来代替这个表s,修改一下函数中的参数就行。只是实现方式不同,结果相同
  78. //进行初始化
  79. Init(&s);
  80. ElemType e=0;
  81. int x;
  82. printf("先将队列初始化之后的头标记为:%d 尾标记为:%d\n\n",s.front,s.rear);
  83. printf("队列的大小为:%d\n\n",Maxsize);
  84. //来五次入队操作
  85. Add(&s,8);
  86. Add(&s,5);
  87. Add(&s,4);
  88. Add(&s,0);
  89. Add(&s,7);
  90. //看一下当前队的长度
  91. x=Length(s);
  92. if(x)
  93. {
  94. printf("操作完成之后,当前队列的长度为:%d\n\n",Length(s));
  95. }
  96. //读取队首元素
  97. x=Get(s);
  98. if(x) //如果x不为0,执行里面的东西
  99. {
  100. printf("当前队列中的队首元素为:%d\n\n",x);
  101. }
  102. //出队操作
  103. Dele(&s,&e);
  104. Dele(&s,&e);
  105. Dele(&s,&e);
  106. x=Get(s);
  107. if(!(x==0&&e==0))
  108. {
  109. printf("出队操作之后,刚刚出队的元素为:%d,当前队首元素为:%d\n\n",e,x);
  110. }
  111. return 0;
  112. }

总结

       循环队列的难点就是如何判断队空和队满,以及当rear指向最后一个位置时,我们再进行入队的操作,还有当front指向最后一个位置,我们再进行出队的操作,都需要队Maxsize进行取模运算,顺序表,链表,栈,队他们的操作都很相似,大家可以对比一下,只要掌握了其中一个的操作,对于其他的操作,都可以迎刃而解,将逻辑内化于心。本人能力有限,如有表述不对的地方,欢迎批评指正。

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

闽ICP备14008679号