queue.h文件
其实这部分文件跟我们的栈的头文件定义是一样的,就是我们的pop和push换成了enqueue跟dequeue
/*
*这部分文件实现我们之前所使用的queue类
*它主要的原理为 后进后出(LILO)
*/
#ifndef _Queue_h
#define _Queue_h
/*
*类型: Queue<ValueType>
*此类建立一个称为队列的线性结构,其中仅从一端添加和删除值。
*这个规定产生了一个(LILO)的行为,它是队列的定义特征。
*基本堆栈操作是dequeue·(把元素从队列中移除)和enqueue(把元素添加到队列中)。
*/
template <typename ValueType>
class Queue{
public:
/*
*构造函数:Queue
*用法:Queue <ValueType> queue
*-----------------------------
*初始化一个空队列
*/
Queue();
//析构函数
~Queue();
/*
*方法:size()
*用法:int n = queue.size();
*--------------------------
*返回队列中元素的个数
*/
int size();
/*
*方法:isEmpty()
*用法:queue.isEmpty();
*--------------------------
*判断队列中元素是否为空
*/
bool isEmpty();
/*
*方法:clear()
*用法:queue.clear();
*--------------------------
*清空队列中的所有元素
*/
void clear();
/*
*方法:enqueue()
*用法:stack.enqueue();
*--------------------------
*向队尾插入一个元素
*/
void enqueue(ValueType);
/*
*方法:pop()
*用法:queue.dequeue();
*--------------------------
*移除队头的一个元素,并返回其值,如果队空 则返回一个错误
*/
ValueType dequeue();
/*
*方法:peek()
*用法:queue.peek();
*--------------------------
*返回队头的值,但是不移除,peek 偷看的意思,如果队空 则返回一个错误
*/
ValueType peek();
#include "queuepriv.h" //私有成员部分
};
#include "queueimpl.cpp" //将实现文件包含进来
#endif
queuepriv.h文件
这部分定义我们的数组结构:
private:
/*栈的链表结构*/
struct Cell{
ValueType data;
Cell *link;
};
/*实例化变量*/
Cell *stack; /*定义一个cell类型的指针,指向栈顶*/
int count; /*用返回栈中的元素个数*/
/* Make it illegal to copy stacks */
Stack(const Stack & value) { }
const Stack & operator=(const Stack & rhs) { return *this; }
queueimpl.cpp文件
#ifdef _Queue_h
#include "error.h"
/*
*构造函数,这个函数要为队列的元素分配存储空间,并为所有的对象进行初始化元素赋值
*/
template <typename ValueType>
Queue<ValueType>::Queue(){
capacity = INITIAL_CAPACITY;
array = new ValueType [capacity];
head = 0;
tail = 0;
}
/*
*析构函数:释放我们之前分配的内存
*/
template <typename ValueType>
Queue<ValueType>::~Queue(){
delete []array;
}
/*
*返回队列中的元素个数,
*/
template<typename ValueType>
Queue<ValueType>::size(){
return (tail + capacity - head) % capacity;
}
/*
*判断队列是否为空,这个判断标准,无论是使用指针还是我们的数组
*判断标准都是tail == head,请注意,这种解释意味着不能允许队列完全填写容量,
*并且必须始终留下一个未使用的空间。
*/
template <typename ValueType>
bool Queue<ValueType>::isEmpty(){
return tail == head;
}
/*
*清空队列,清除方法不需要考虑环形缓冲区(即循环队列)中存在的任何现有数据的位置,
*并且可以简单地重置头部和尾部索引。
*/
template <typename ValueType>
void Queue<ValueType>::clear(){
head = tail = 0;
}
/*
*入队列,此方法必须首先检查以确定元素是否有足够的空间供其插入,并在必要时
*扩展数组存储空间。否则不可能区分队列为空的情况与队列完全充满时的情况,
*当该大小小于容量时,该实现会扩展队列
*/
template <typename ValueType>
void Queue<ValueType>::enqueue(ValueType element){
if(size = capacity - 1) {expandCapacity();}
array[tail] = element;
tail = (tail + 1) % capacity;
}
/*
*出队列,这个方法必须检查我们的队列是否为空,如果是,那就报错
*/
template <typename ValueType>
ValueType Queue<ValueType>::dequeue(){
if (isEmpty())
{
error("dequeue: Attempting to dequeue an empty queue");
}
ValueType result = array[head];
head = (head + 1) % capacity;
return result;
}
/*
*查看队头元素
*/
template <typename ValueType>
ValueType Queue<ValueType>::peek(){
if (isEmpty())
{
error("peek: Attempting to peek at an empty queue");
}
return array[head];
}
/*
*扩展容量,只要空间不足,这个私有方法将动态数组的容量加倍。
*为此,它必须分配一个新数组,将所有元素从旧数组复制到新的数组,并释放旧存储。
*请注意,此实现还将所有元素都移回数组的开头。
*/
template <typename ValueType>
void expandCapacity(){
ValueType *oldArray = array;
int count = Size();
capacity = capacity *2;
array = new ValueType[capacity];
for (int i = 0; i <= count; i++)
{
array[i] = oldArray[(head + i) % capacity];
}
head = 0;
tail = count;
delete []oldArray;
}
#endif
这里有个算法,size的算法,如下:
return (tail + capacity - head) % capacity;
我们来看看为什么会有这个算法,假设一开始的队列如下’
也就是这种情况:
最后模上我们的容量 就完成了。