数据结构学习笔记6——队列

来源:互联网 发布:1688一键传淘宝教程 编辑:程序博客网 时间:2024/06/05 03:12

1,综述

队列(queue)是一种受限制的线性表,其属性与看电影排队类似,新加入的必须排在队尾(enqueue,入队),先离开的必须从队首开始(dequeue,出队)。因此,队列是按照到达的顺序来删除元素的,即先进先出(First In First Out).

队列的ADT:(Queue.h)
/********************************************************/// 用模板实现队列(Queue)的基类定义// 队列,先进先出(FIFO)的线性表/********************************************************/#pragma once#include "Public.h"template<class E>class Queue{public:Queue() {}virtual ~Queue() {}virtual void clear() = 0;// 入队,只能从队尾插入virtual void enqueue(const E& it) = 0;// 出队,只能从队首删除,返回类型不能是引用,因为返回的队首值已经不存在了virtual E dequeue() = 0;// 返回队首的值,返回类型是const引用,所以你能获取值,但不能改变它virtual const E& frontValue()const = 0;// 返回栈中当前存储的元素个数virtual int length() const = 0;};


队列的实现方式有两种:顺序队列(用数组实现)和链式队列(用单向链表实现)。

2,顺序队列(array based queue)

用数组模拟队列,首先想到的,就是把队首放在a[0]位置,剩下的依次排放,新元素入队就放在后面排队,出队的时候,就必须后面所有的元素都往前移一位,就好像我们排队的时候,最前面的人走了,后面所有人必须都往前走一步,队伍才能前进一样。但是这样会耗费态度的资源。所以将其改进为不强制要求队首必须在a[0],只要能知道队首所在的数组下标即可。但是这样一来,一旦发生出队,a[0]和队首之间的内存就被浪费了,永远都没办法利用。改进的方案是,当如队到达数组的最后一个位置a[len-1]后,开始向a[0]填充元素,但不能越过队首。这样一来,直线的排列方式实际上已经变成圆环形了。







代码实现:
ArrayQueue.h:
/********************************************************/// 用数组实现顺序队列(array based queue)的定义// 继承基类栈 Queue<E>/********************************************************/#pragma once#include "Queue.h"const size_t defaultQSize = 5;//Queue数据的默认长度template<class E>class AQueue : public Queue<E>{private:E* data;   //存储Queue数据的数组int front; //队首的数组下标int rear;  //队尾的数组下标+1int maxSize;//简单实现,只开辟一次空间,所以有最大大小int iNr;   //队列中的元素个数,队列长度public:AQueue(size_t size = defaultQSize);~AQueue();void clear();// 入队,只能从队尾插入void enqueue(const E& it);// 出队,只能从队首删除,返回类型不能是引用,因为返回的队首值已经不存在了E dequeue();// 返回类型是const引用,所以你能获取栈顶的值,但不能改变它const E& frontValue()const;// 返回栈中当前存储的元素个数int length() const;};

ArrayQueue_Def.h:
/********************************************************/// 用数组实现顺序队列(array based queue)的定义// 继承基类栈 Queue<E>// 此处实现AQueue<E>的成员函数/********************************************************/#pragma once#include "ArrayQueue.h"// 定义构造函数,开辟空间template<class E>AQueue<E>::AQueue(size_t size = defaultSize) : front(0), rear(0),iNr(0),maxSize(size){data = new E[size];}template<class E>AQueue<E>::~AQueue(){delete[] data;}// 清空栈,只是修改top下标,不收回内存template<class E>void AQueue<E>::clear(){front = rear = iNr = 0;}// 入队,只能从队尾插入template<class E>void AQueue<E> ::enqueue(const E& it){Assert(iNr < maxSize, "队列已满");// 小于maxSize时就是rear,等于maxSize时变成0rear %= maxSize;data[rear++] = it;iNr++;}// 弹出栈顶元素template<class E>E AQueue<E> ::dequeue(){Assert(iNr > 0, "空队列");E it = data[front++]; //front下移一位front %= maxSize;     // 小于maxSize时就是front,等于maxSize时变成0iNr--;return it;}// 获取栈顶元素template<class E>const E& AQueue<E> ::frontValue() const{Assert(iNr > 0, "空栈");return data[front];}// 返回栈中元素个数template<class E>int AQueue<E>::length() const{return iNr;}


3,链式队列

链式队列是对单向链表的简化。需要注意的是,这里front不再是指向队首,front里面不存储队列中任意一个元素的数值,front->next存储的才是队首元素。

LinkedQueue.h:
/********************************************************/// 用模板实现链式队列(Linked Queue)的定义// 是单向链表的简化// 继承基类 Queue<E>/********************************************************/#pragma once#include "Queue.h"// 1,定义节点类模板template<class E>class QNode{public:E element; //本结点存储的元素值QNode* next;//指向下一结点的指针QNode(const E& elemval, QNode* nextval = NULL) :element(elemval), next(nextval) {}QNode(QNode* nextval = NULL) :next(nextval) {}};// 2,定义链表类模板template<class E>class LQueue : public Queue<E>{private:QNode<E>* front; //队首QNode<E>* rear;  //队尾int cnt;         //链表中当前存储的元素个数void init();     //初始化public:LQueue();~LQueue();void print() const;void clear();// 入队,只能从队尾插入void enqueue(const E& it);// 出队,只能从队首删除,返回类型不能是引用,因为返回的队首值已经不存在了E dequeue();// 返回栈中当前存储的元素个数int length() const;// 返回队首的值,返回类型是const引用,所以你能获取值,但不能改变它const E& frontValue()const;};

LinkedQueue_Def.h:
/********************************************************/// 用模板实现链式队列(Linked Queue)的定义// 是单向链表的简化// 继承基类 Queue<E>// 本文件实现成员函数的定义/********************************************************/#pragma once#include "LinkedQueue.h"template<class E>void LQueue<E>::init(){//所有指针指向新开的空间front = rear = new QNode<E>();cnt = 0;}//构造函数template<class E>LQueue<E>::LQueue(){//构造时只开辟一个节点的空间init();}//析构函数template<class E>LQueue<E>::~LQueue(){clear();delete front; //空的首节点也不能留}//打印所有元素template<class E>void LQueue<E>::print() const{Node<E>* temp = front->next; //head中不存储数据,head->next中才有数据while (NULL != temp){//此处暗示类型E必须定义了“<<”操作,否则报错cout << temp->element << endl;temp = temp->next;}}//清空链表template<class E>void LQueue<E>::clear(){QNode<E>* temp = front->next;//删除除front之外的所有节点while(NULL != temp){front->next = temp->next;delete temp;temp = front->next;}rear = front;cnt = 0;}//入队template<class E>void LQueue<E>::enqueue(const E& it){rear = rear->next = new QNode<E>(it);cnt++;}//出队template<class E>E LQueue<E>::dequeue(){// 由于front节点不存储真实的内容,要删除的不是front,而是front->nextAssert(cnt != 0, "队列为空");QNode<E>* temp = front->next;E it = front->next->element;// front节点的位置不变,但是front->next指向下一个front->next = temp->next;// 要删除的是最后一个元素if (temp == rear){rear = front;}delete temp;cnt--;return it;}// 返回个数template<class E>int LQueue<E>::length() const{return cnt;}template<class E>const E& LQueue<E>::frontValue()const{return front->next->element;}


0 0
原创粉丝点击