数据结构循环队列C++实现

数据结构循环队列C++实现,第1张

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 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 struct LinkNode { T data; //数据域 LinkNode * link; //指针域,指向下一个节点 LinkNode() //仅初始化指针的构造函数 { LinkNode *ptr = nullptr; link = ptr; } LinkNode(const T& item, LinkNode *ptr = nullptr) //初始化数据和指针成员的构造函数 { data = item; link = ptr; } };

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

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

代码如下;

#pragma once
//顺序队列,存储形式是数组。

为了有效利用内存,设计成循环队列 # include # include # include "Queue.h" using namespace std; template class SeqQueue :public Queue //继承时注意Queue也是类模板,后面加区别普通的类 { public: //如果不加public,权限为private SeqQueue(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 friend ostream & operator<<(ostream & out, SeqQueue &sq);//重载<<输出队列内容 private: int rear, front; //队尾和队首的指针,同链式栈一样,不是真正的指针,而是下标。

front是第一个元素的下标,rear是最后一个元素下一个位置的坐标 T * elements; //指向存放数据的数组的指针 int maxSize; //队伍最大可容纳元素的个数 }; //构造函数 template SeqQueue::SeqQueue(int sz):front(0),rear(0),maxSize(sz) //这里的sz不允许使用默认参数 { //建立一个最大容量为maxSize的空队列 //rear = front = 0; //maxSize = sz; elements = new T[maxSize]; assert(elements != nullptr);//断言函数,括号里的内容成立,则继续执行代码;否则,终止代码的执行 } //新元素入队尾 template bool SeqQueue::EnQueue(const T& x) { if (IsFull() == true) return false; //队列满则插入失败 elements[rear] = x; //队尾位置插入新元素 rear = (rear+1)%maxSize; //队尾指针更新 return true; } //队头元素出队 template bool SeqQueue::DeQueue(T& x) { if (IsEmpty()) return false; x = elements[front]; front = (front + 1) % maxSize; //队头指针加一 return true; } //获取队头元素 template bool SeqQueue::getFront(T &x) { if (IsEmpty()) return false; x = elements[front]; return true; } //求队列元素的个数 template int SeqQueue::getSize() const { return (rear - front + maxSize) % maxSize; //加maxSize是为了保证队列只入队且队列入满时rear=0,front=1,此时rear-front=-1, //此时元素个数为maxSize-1,由此加上maxSize可以得到正确结果 } template ostream & operator<<(ostream & out, SeqQueue &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
#include "SeqQueue.h"
using namespace std;
int main()
{

	SeqQueue sq(10);
	for (int i = 0; i < 10; i++)
		sq.EnQueue(i);
	cout << sq << endl;
}

结果如下图所示:

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/673863.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-04-19
下一篇2022-04-19

发表评论

登录后才能评论

评论列表(0条)

    保存