1.队列的概念

队列只允许在表的一端插入,另一端删除。允许插入的一端叫做队尾,允许删除的一端叫做对首。队列的特性叫“先进先出”。和栈一样,队列的存储形式也有两种,基于数组的存储表示和基于链表的存储表示。本文先实现基于数组的存储队列,也叫顺序队列。在顺序队列中设置两个指针,front和rear,front指示队头的位置,rear指示队尾的位置(说是指针,实际仍不是c语言的指针*,而是类似下标或索引的作用)。如下图所示:

  1. 当队列为空时,front=rear=0;
  2. 有新元素入队时,先将新元素添加到rear所指的位置,然后再讲rear加1;因而rear指示了实际队尾位置的下一个位置,即下一个元素应当加入的位置。如上图的图b所示。
  3. 当队首元素出队时,先将队首元素记录下来,然后front指针加1,指示新的队头的位置,然后将记录的元素值返回,如上图c所示。

2.顺序队列存在的问题

如果上图图c中B再出队,则front会在C的位置,这样原来的索引为0和1的内存就会是空的,这时数组的前端还有空位置,这就造成了资源的浪费。所以,为了能充分的利用数组中的存储空间,把数组的前端和后端连接起来,形成一个闭环,这样的队列叫做循环队列,如下图所示

上图循环队列最多存maxSize=8个元素,这样如果一直往队列中加入新元素,则当rear=maxSize-1=7时,如果再进一个元素,则rear就会变为0;同理,若此时一直往外出队数据,则当H出队后front也会变为0。这样的操作可以利用取余%来实现:

队头指针进1:front = ( front + 1)  %maxSize;

队尾指针进1:rear= (rear + 1)%maxSize;

3.循环队列队满和队空的判断条件

如果循环队列出队速度快于入队速度,则front会追上rear,此时front == rear,队列为空;

如果入队速度快于出队速度,则rear会追上front,但是为了区别于上面的队空条件(front ===rear),我们用(rear + 1)%maxSize  == front来判断是否队满。也就是说,当rear指到front的前一个位置时,我们就认为队列满了,如上图总的最后一个小图所示,此时rear指向的位置不能再存元素了,如果不留这个位置,再入队最后一个新元素,此时rear == front,这时队列实际是满的,可代码会认为这是队空的条件,进而判断此时队列为空,因此产生混淆。所以,当rear指到front的前一个位置时,我们就认为队列满了,即(rear + 1)%maxSize  == front,队满,队列不再能入队新元素。

这样构成的循环队列最多能存放maxSize - 1个元素。

4.队列基类的头文件"Queue.h"

这个头文件定义了队列通用的一些方法,循环队列,包括后面的链式队列均可以继承实现多态。代码如下:

#pragma once
const int maxSize = 50;  //顺序队列的最大元素个数template <class T>
class Queue
{
public:Queue() {};~Queue() {};virtual bool EnQueue(const T& x) = 0; //新元素入队virtual bool DeQueue(T& x) = 0;       //队头元素出队virtual bool getFront(T& x) = 0;      //获取队头元素virtual bool IsEmpty() const = 0;          //判断队列是否为空virtual bool IsFull() const = 0;            //判断队列是否满。顺序队列需要,链式队列不需要,但仍要重写virtual int getSize() const = 0;            //求队列元素的个数
};//用struct定义节点,链式队才用的到
template <class T>
struct LinkNode {T data; //数据域LinkNode<T> * link; //指针域,指向下一个节点LinkNode() //仅初始化指针的构造函数{LinkNode<T> *ptr = nullptr;link = ptr;}LinkNode(const T& item, LinkNode<T> *ptr = nullptr) //初始化数据和指针成员的构造函数{data = item;link = ptr;}
};

5.循环队列头文件“SeqQueue.h”

该头文件定义循环队列的类以及其属性即接口实现,重写了队列基类Queue的函数,实现多态。代码如下;

#pragma once
//顺序队列,存储形式是数组。为了有效利用内存,设计成循环队列
# include <iostream>
# include <assert.h>
# include "Queue.h"
using namespace std;template <class T>
class SeqQueue :public Queue<T>   //继承时注意Queue也是类模板,后面加<T>区别普通的类
{
public:                                     //如果不加public,权限为privateSeqQueue(int sz=10);                   //构造函数~SeqQueue() { delete[] elements; }  //[]紧跟delete,表明释放的elements地址是一个数组,而不是单个变量bool IsFull() const{ return ((rear + 1) % maxSize == 0) ? true : false; }//是否队满bool IsEmpty() const { return (rear == front) ? true : false; }  //是否队空bool EnQueue(const T& x);           //新元素入队bool DeQueue(T& x);                 //队头元素出队bool getFront(T& x);                //获取队头元素void makeEmpty() { rear = front = 0; }//清空队列(其实队列内容未被修改,只是将指针置0)int getSize() const ;                        //求队列元素的个数template <class R>friend ostream & operator<<(ostream & out, SeqQueue<R> &sq);//重载<<输出队列内容
private:int rear, front;   //队尾和队首的指针,同链式栈一样,不是真正的指针,而是下标。front是第一个元素的下标,rear是最后一个元素下一个位置的坐标T * elements;      //指向存放数据的数组的指针int maxSize;       //队伍最大可容纳元素的个数
};//构造函数
template <class T>
SeqQueue<T>::SeqQueue(int sz):front(0),rear(0),maxSize(sz)  //这里的sz不允许使用默认参数
{//建立一个最大容量为maxSize的空队列//rear = front = 0;//maxSize = sz;elements = new T[maxSize];assert(elements != nullptr);//断言函数,括号里的内容成立,则继续执行代码;否则,终止代码的执行
}//新元素入队尾
template <class T>
bool SeqQueue<T>::EnQueue(const T& x)
{if (IsFull() == true)return false;   //队列满则插入失败elements[rear] = x; //队尾位置插入新元素rear = (rear+1)%maxSize; //队尾指针更新return true;
}//队头元素出队
template <class T>
bool SeqQueue<T>::DeQueue(T& x)
{if (IsEmpty()) return false;x = elements[front];front = (front + 1) % maxSize; //队头指针加一return true;
}//获取队头元素
template <class T>
bool SeqQueue<T>::getFront(T &x)
{if (IsEmpty()) return false;x = elements[front];return true;
}//求队列元素的个数
template <class T>
int SeqQueue<T>::getSize() const
{return (rear - front + maxSize) % maxSize; //加maxSize是为了保证队列只入队且队列入满时rear=0,front=1,此时rear-front=-1,//此时元素个数为maxSize-1,由此加上maxSize可以得到正确结果
}template <class R>
ostream & operator<<(ostream & out, SeqQueue<R> &sq)
{out << "front = " << sq.front << ",rear = " << sq.rear << endl;for (int i = sq.front; i != sq.rear; i = (i + 1) % sq.maxSize){out << i << " : " << sq.elements[i] << endl;}return out;
}

6.代码测试

放在“循环队列.cpp”文件中,老规矩只做简单测试,代码如下:

#include<iostream>
#include "SeqQueue.h"
using namespace std;
int main()
{SeqQueue<int> sq(10);for (int i = 0; i < 10; i++)sq.EnQueue(i);cout << sq << endl;
}

结果如下图所示:

数据结构循环队列C++实现相关推荐

  1. python环形队列_Python 实现数据结构-循环队列的操作方法

    今天我们来到了循环队列这一节,之前的文章中,我介绍过了用python自带的列表来实现队列,这是最简单的实现方法. 但是,我们都知道,在列表中删除第一个元素和删除最后一个元素花费的时间代价是不一样的,删 ...

  2. 循环队列的java结构_Java数据结构——循环队列

    普通顺序队列存在的问题 在普通顺序队列中,入队的操作就是先将尾指针rear右移一个单位,然后将元素值赋值给rear单位.出队时,则是头指针front后移一个单位.像这样进行了一定数量的入队和出队操作后 ...

  3. 数据结构--循环队列

    循环队列 图片讲解

  4. [数据结构]-循环队列

    循环队列 package com.cn.jichu.day09;public class LoopQueue<E> {/*** 数组*/private E[] data;/*** 头指针, ...

  5. 数据结构-循环队列(C语言代码)

    循环队列就是将队列存储空间的最后一个位置绕到第一个位置,形成逻辑上的环状空间,供队列循环使用.在循环队列结构中,当存储空间的最后一个位置已被使用而再要进入队运算时,只需要存储空间的第一个位置空闲,便可 ...

  6. Python写数据结构:循环队列

    #!/usr/bin/python3.5 #_*_coding:utf-8_*_class Queue():def __init__(self,capacity):self.queue = [None ...

  7. c语言 数据结构 循环队列

    #include<stdio.h> #include<stdlib.h> #define QueueSize 100 typedef char DataType; typede ...

  8. 数据结构之——队列与循环队列

    数据结构学习之--队列与循环队列 什么是队列(Queue) 队列基于动态数组的实现及时间复杂度分析 优化队列 循环队列(LoopQueue) 什么是队列(Queue) 队列(Queue)同栈(stac ...

  9. 【数据结构】队列-顺序队列、循环队列、链队、双端队列

    定义 队列是只允许在一端进行插入,而在另一端进行删除的线性表. 队头(Front):允许删除的一端,又称为队首. 队尾(Rear): 允许插入的一端. 先进入队列的元素必然先离开队列,即先进先出(Fi ...

最新文章

  1. 3-4 第三天 Generator生成器
  2. java 十进制 左移,java移位运算符之十进制转二进制
  3. 计算机防火墙不能更改,win7系统更新防火墙设置不能更改的解决方法
  4. 文字双击之后默认蓝底白色
  5. 用vuejs如何实现ajax,vue.js如何实现ajax
  6. selenium+python,解决selenium弹出新页面,无法定位元素的问题(报错:Unable to locate element:元素)
  7. Oracle 向上递归、向下递归
  8. IntelliJ IDEA如何修改背景颜色样式
  9. 在windows2003, mysql5.0, PHP 4.4.4下的bugfree1.1打包
  10. NIO系列六:流行 NIO Framework netty 和 mina 性能测评与分析
  11. 服务器怎么关闭终端依然运行node,关闭控制台后如何永久运行node.js应用程序?...
  12. echart 世界地图发光_echarts生成世界地图,百度echarts生成世界地图方法
  13. java可达性_java 垃圾回收总结(可达性分析 引用分类
  14. Python常用库汇总
  15. 前端怎么加粗字体_Variable Fonts 可变形字体
  16. VS2015+MATLAB2016b混合编程
  17. 亲自操作,有用的win10遇到“已禁用输入法”无法启动中文输入法的问题-提示已禁用输入法解决方案
  18. 关于按键精灵url的post方法返回值为空
  19. uniapp 微信登录取消授权,以及不等待你做出授权选择就执行方法体
  20. 难道我买了一个假路由器?解决光猫引出的路由器网速很慢的问题

热门文章

  1. Spring-Core 中文翻译+总结文档(上)
  2. 分享:从编程中悟出的八字箴言
  3. 复习IO流复制文件时,文件损坏并且文件变得超大(FileInputStream和FileOutputStream)数组复制
  4. [教你做小游戏] 《五子棋》怎么判断输赢?你能5分钟交出代码吗?
  5. 【考研经验】双非二战山东大学计算机技术初试第二经验贴
  6. VS中进行C#编码时智能提示由英文切换为中文
  7. 监控系统存储服务器和磁盘阵列,浅谈磁盘阵列如何应用于监控储存领域
  8. ionic 环境搭建,运行项目到浏览器,android手机,模拟器
  9. 判断点是否在点组成的封闭区域内c++
  10. 小米电视es65、ea65、ex65和ec65区别