当前位置:   article > 正文

C++实现普通队列,循环队列的基本操作(初始化,入队,出队,获取队列首元素等)_循环队列的怎么赋初值

循环队列的怎么赋初值

队列是一种先进先出(FIFO,First-In-First-Out)的线性表,通常用链表或者数组来实现。队列只能在队尾插入元素,只能在队首删除元素。

队列的一些性质:

1.出队方案唯一

2.队首元素先出

3.新元素插入队尾

线性队列的初始化:

  1. #include <iostream>
  2. using namespace std;
  3. class Queue{
  4. private:
  5. int *data; //定义指向整型的指针,从而动态开辟内存
  6. int head,tail,length; //head指向队首,tail指向队尾,length表示队列的长度
  7. public:
  8. Queue (int length_input){ //构造函数,对新声明的队列对象进行初始化
  9. data = new int [length_input]; //动态开辟100个整型数据的空间
  10. length = length_input; //为队列的长度赋初始值
  11. head = 0; //起初head为0,表示head值未改变的情况下,一直指向首元素
  12. tail = -1; //tail初始值为-1,表示此时队列为空,无任何数据元素
  13. }
  14. ~Queue(){
  15. delete [] data; //析构函数,删除动态开辟的内存
  16. }
  17. };
  18. int main() {
  19. Queue queue(100); //声明一个队列对象,并初始化
  20. return 0;
  21. }
入队操作:

  1. #include <iostream>
  2. using namespace std;
  3. class Queue{
  4. private:
  5. int *data; //定义指向整型的指针,从而动态开辟内存
  6. int head,tail,length; //head指向队首,tail指向队尾,length表示队列的长度
  7. public:
  8. Queue (int length_input){ //构造函数,对新声明的队列对象进行初始化
  9. data = new int [length_input]; //动态开辟100个整型数据的空间
  10. length = length_input; //为队列的长度赋初始值
  11. head = 0; //起初head为0,表示head值未改变的情况下,一直指向首元素
  12. tail = -1; //tail初始值为-1,表示此时队列为空,无任何数据元素
  13. }
  14. ~Queue(){
  15. delete [] data; //析构函数,删除动态开辟的内存
  16. }
  17. void push(int element){ //入队操作,只能从队列的尾部插入数据元素
  18. if(tail+1 < length){ //队列未满的时候才能插入,否则则插入失败
  19. ++tail; //队尾指针先往后移动一位
  20. data[tail] = element; //再插入队尾指针指向的位置
  21. }
  22. }
  23. void output(){
  24. for(int i = head;i <= tail;i++){ //从队首一直遍历到队尾
  25. cout << data[i] << " ";
  26. }
  27. cout << endl;
  28. }
  29. };
  30. int main() {
  31. Queue queue(100); //声明一个队列对象,并初始化
  32. for(int i = 1;i <= 10;++i){
  33. queue.push(i); //将1-10这10个数据元素依次插入队列中
  34. }
  35. queue.output(); //调用输出的方法
  36. return 0;
  37. }
效果图:



出队以及获取队首元素的操作:

  1. #include <iostream>
  2. using namespace std;
  3. class Queue{
  4. private:
  5. int *data; //定义指向整型的指针,从而动态开辟内存
  6. int head,tail,length; //head指向队首,tail指向队尾,length表示队列的长度
  7. public:
  8. Queue (int length_input){ //构造函数,对新声明的队列对象进行初始化
  9. data = new int [length_input]; //动态开辟100个整型数据的空间
  10. length = length_input; //为队列的长度赋初始值
  11. head = 0; //起初head为0,表示head值未改变的情况下,一直指向首元素
  12. tail = -1; //tail初始值为-1,表示此时队列为空,无任何数据元素
  13. }
  14. ~Queue(){
  15. delete [] data; //析构函数,删除动态开辟的内存
  16. }
  17. void push(int element){ //入队操作,只能从队列的尾部插入数据元素
  18. if(tail+1 < length){ //队列未满的时候才能插入,否则则插入失败
  19. ++tail; //队尾指针先往后移动一位
  20. data[tail] = element; //再插入队尾指针指向的位置
  21. }
  22. }
  23. void pop(){
  24. if(tail < 0){ //队列为空,出队失败
  25. return;
  26. }
  27. ++head; //队首指针后移,表示原来队首已出列
  28. }
  29. int top(){
  30. if(tail > -1){ //队列不为空的情况下才能获取队首元素
  31. return data[head];
  32. }
  33. }
  34. void output(){
  35. for(int i = head;i <= tail;i++){ //从队首一直遍历到队尾
  36. cout << data[i] << " ";
  37. }
  38. cout << endl;
  39. }
  40. };
  41. int main() {
  42. Queue queue(100); //声明一个队列对象,并初始化
  43. for(int i = 1;i <= 10;++i){
  44. queue.push(i); //将1-10这10个数据元素依次插入队列中
  45. }
  46. queue.output(); //调用输出的方法
  47. cout << "当前的队首元素为:" << queue.top() << endl;
  48. queue.pop(); //出队
  49. queue.output(); //调用输出的方法
  50. cout << "出队操作后的队首元素为:" << queue.top() << endl;
  51. return 0;
  52. }
效果图:



可是,普通队列有什么局限性呢?比如说我们动态申请了能够100个整型数据的数组来容纳队列中的元素,而正如函数中的判断语句:

tail+1 >= length

当tail的值达到length-1时,实际上就说明“队列”已经满了。但是实际情况真的是如此吗?

比如说在队列操作的过程中,不断地有元素出队,而且不断地有元素入队,那么的话,当tail的值达到length-1时,实际上就说明“队列”已经满了,但是如果此时head的值不是0的话,实际上这个队列是没有装满100个数据元素的,head之前的空间都将会被浪费。这种现象在我们程序设计中,称作“假溢出”现象

假溢出:系统作为队列用的存储区还没有满,但队列却发生了溢出,我们把这种现象称为"假溢出"。

假溢出百度百科描述

我们这时候肯定会想,如果这时候队尾指针tail能够继续越过队尾,往0—head之间增添元素的话,那么就可以避免空间的浪费了,所以呢,基于这种想法,我们便引进了循环队列来对当前队列进行改进

循环队列,顾名思义,就是以循环的方式来存储队列。回顾一下我们之前用到的队尾标记 tail。对于循环队列,当队尾标记 tail 到达数组的上界后,如果队列内的元素个数没有达到容量上限,就跳转到数组的起始位置,也就是 0 的位置;队首标记 head 到达数组上界采取同样的处理。通过这样的方法,我们就能够最大化利用内存空间,避免“假上溢”的情况出现啦。

循环队列:


下面我们将改进线性队列的代码,实现循环队列的一些基本操作

循环队列的一些性质:

1.在循环队列里,如果容量没有达到上限,当队尾队首标记达到数组上界后,就跳转到数组起始位置

2.在线性队列里,当 tail 达到队列上限后,继续插入就会发生“假上溢”的情况

3.循环队列里可通过统计队列里元素个数,判断能否继续往队列里插入元素

首先,我们增加一个count变量来计算入队的元素个数,这样的话,当count = length的时候,才表示真正的队列“上溢”,所以呢,对于循环队列的入队操作,可分两种情况讨论:

1.如果队尾指针此时并未指向队列的最后一位,那么队尾指针直接前移

2.当队尾指针此时指向最后一位时,那么当队列未满时,则队尾指针将跳转至数组起始位置

第一种情况下,我们可以写成:

tail = tail + 1;
而第二种情况下,我们可以写成:

tail = (tail + 1)% length
所以呢,两种情况综合起来,则可写成:

tail = (tail + 1) % length;
同样的,出队操作时,则有:

head = (head + 1) % length;
这里特别需要注意的是,循环队列的遍历输出时,循环截止条件不再是head <= tail,而是head != tail +1,这是为什么呢?原因其实也很简单,因为 当队尾队首标记达到数组上界后,就跳转到数组起始位置,所以tail是可能小于head的,而无论是head<tail,亦或是head > tail,都是顺时针从head循环至tail,所以可用此循环截止条件:

  1. for(int i = head;i != tail + 1;i = (i + 1)%length){ //从队首一直遍历到队尾,当遍历到最后一位时,跳转至数组起始位置
  2. //特别注意此时循环截止的条件应该是i != tail + 1,因此可能tail的值小于head
  3. cout << data[i] << " ";
  4. }
循环队列初始化,入队出队等操作完整代码实现:

  1. #include <iostream>
  2. using namespace std;
  3. class Queue{
  4. private:
  5. int *data; //定义指向整型的指针,从而动态开辟内存
  6. int head,tail,length,count; //head指向队首,tail指向队尾,length表示队列的长度,count用于记录队列中元素个数,从而判断队列是否已满
  7. public:
  8. Queue (int length_input){ //构造函数,对新声明的队列对象进行初始化
  9. data = new int [length_input]; //动态开辟100个整型数据的空间
  10. length = length_input; //为队列的长度赋初始值
  11. head = 0; //起初head为0,表示head值未改变的情况下,一直指向首元素
  12. tail = -1; //tail初始值为-1,表示此时队列为空,无任何数据元素
  13. count = 0;
  14. }
  15. ~Queue(){
  16. delete [] data; //析构函数,删除动态开辟的内存
  17. }
  18. void push(int element){ //入队操作,只能从队列的尾部插入数据元素
  19. if(count < length){ //队列未满的时候才能插入,否则则插入失败
  20. tail = (tail + 1) % length; //分两种情况,如果队尾指针此时并未指向队列的最后一位,那么队尾指针直接前移,而当队尾指针此时指向最后一位时
  21. data[tail] = element; //那么当队列未满时,则队尾指针将跳转至数组起始位置,再将数据元素插入队尾指针指向的位置
  22. ++count; //入队成功,队列中元素数量加一
  23. }
  24. }
  25. void pop(){
  26. if(count < 0){ //队列为空,出队失败
  27. return;
  28. }
  29. head = (head + 1) % length; //同样,根据循环队列的性质得出
  30. --count; //出队成功,队列中元素数量减一
  31. }
  32. int top(){
  33. if(count > 0){ //队列不为空的情况下才能获取队首元素
  34. return data[head];
  35. }
  36. }
  37. void output(){
  38. for(int i = head;i != tail + 1;i = (i + 1)%length){ //从队首一直遍历到队尾,当遍历到最后一位时,跳转至数组起始位置
  39. //特别注意此时循环截止的条件应该是i != tail + 1,因此可能tail的值小于head
  40. cout << data[i] << " ";
  41. }
  42. cout << endl;
  43. }
  44. };
  45. int main() {
  46. Queue queue(100); //声明一个队列对象,并初始化
  47. for(int i = 1;i <= 10;++i){
  48. queue.push(i); //将1-10这10个数据元素依次插入队列中
  49. }
  50. queue.output(); //调用输出的方法
  51. cout << "当前的队首元素为:" << queue.top() << endl;
  52. queue.pop(); //出队
  53. queue.output(); //调用输出的方法
  54. cout << "出队操作后的队首元素为:" << queue.top() << endl;
  55. return 0;
  56. }

效果图:


 





如有错误,还请指正,O(∩_∩)O谢谢



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

闽ICP备14008679号