先介绍一下队列:
队列(queue)在计算机科学中,是一种先进先出的线性表。
它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。 由于队列在队头进行删除,队尾进行插入,所以用链表进行实现就比较方便。
队列采用的FIFO(first in first out),新元素(等待进入队列的元素)总是被插入到链表的尾部,而读取的时候总是从链表的头部开始读取。每次读取一个元素,释放一个元素。所谓的动态创建,动态释放。因而也不存在溢出等问题。由于链表由结构体间接而成,遍历也方便。
用下图来表示队列的实现方式:
队列的基本运算:
push(data)//插入
pop()//删除
front()//返回队头元素
rear()//返回队尾元素
size()//返回队列中元素的个数
下面用代码进行实现:
#include<iostream>
#include<assert.h>
using namespace std;
template <typename T>
struct QueueNode
{
T _a;//数据
QueueNode *next;//指向下一个节点
QueueNode(const T& X = T())
:_a(X)
,next(NULL)
{}
};
template <typename T>
class Queue
{
public:
typedef struct QueueNode<T> Node;//类型重定义
Queue()//构造函数
:_rear(NULL)
,_front(NULL)
{}
Queue(const Queue<T>& Q)//拷贝构造函数
:_rear(NULL)
,_front(NULL)
{
if(Q._front)
{
Node* p1 = Q._front;
_front = _BuyNode(Q._front->_a);
_rear = _front;
while(p1)
{
Node* NewNode = _BuyNode(p1->_a);
_rear->next = NewNode;
p1 = p1->next;
}
}
}
~Queue()//析构函数
{
Node* p = _front;
while(p)//这里需要将节点一个一个释放
{
Node* p1 = p->next;
delete p;
p = p1;
}
_front = NULL;
_rear = NULL;
}
void Pop()//删除
{
if(_front == _rear)
{
delete _front;
_front = _rear = NULL;
}
else
{
Node* p = _front;
_front = p->next;
delete p;
}
}
void Push(const T& data)//插入
{
Node* node = _BuyNode(data);
if(_front == NULL)
{
_front = _rear = node;
}
else
{
_rear->next = node;
_rear = node;
}
}
int Size()//返回队列中元素的个数
{
int count = 0;
Node* p = _front;
while(p)
{
count++;
p = p->next;
}
return count;
}
T& Front()//返回队头元素
{
assert(Size());
return _front->_a;
}
T& Rear()//返回队尾元素
{
assert(Size());
return _rear->_a;
}
bool Empty()//判断队列是否为空
{
return !(_front);
}
protected:
Node* _BuyNode(T data)//创建新的节点
{
Node* tmp = new Node;
tmp->_a = data;
tmp->next = NULL;
return tmp;
}
Node* _rear;//队尾
Node* _front;//队头
};
int main()
{
//构建一个队列的对象Q
Queue<int> Q;
//插入6个元素
Q.Push(1);
Q.Push(2);
Q.Push(3);
Q.Push(4);
Q.Push(5);
Q.Push(6);
//删除两个元素
Q.Pop();
Q.Pop();
Q.Front();//返回队头元素
Q.Rear();//返回队尾元素
Q.Size();//返回队列元素的个数
Q.Empty();//判断是否为空队列
while(Q.Size())//输出队列中的元素
{
cout<<Q.Front()<<" ";
Q.Pop();//由于只可访问队头元素,所以每次将队头元素删除才可访问下一元素
}
cout<<endl;
return 0;
}
结果:
以上代码的不足之处:由于输出元素时将队头元素删除,所以输出完后队列就成空队列了。