队列是一种操作受限的线性表数据结构。对于它的操作需要遵守的规则是“先进者先出,后进者后出”,就像我们排队买票一样,排在队伍前边的先买到票先离开,排在队伍后边后买到票后离开,因此队列只支持两种操作,即入队和出队,其中入队是从队列的尾部插入新的元素,而出队则是在队列的头部弹出元素。由于该数据结构的特性,使其在实际中有很多的应用,比如消息队列、阻塞队列、并发队列等。
本文根据队列的基本特性实现了三种基本队列,分别是顺序队列,链式队列和循环队列。
完整实现详见于https://github.com/hitskyer/course/tree/master/dataAlgorithm/liuyanfu/Queue
1 、顺序队列
1.1、接口定义
#ifndef _ARR_QUEUE_H
#define _ARR_QUEUE_H
typedef unsigned int UINT;
template<typename T>
class ArrQueue
{
public:
ArrQueue(void);
ArrQueue(const UINT& InitSize); //初始化队列的总长度
~ArrQueue(void);
bool enqueue(const T& data); //入队
bool dequeue(); //出队
UINT getlength() const; //获取队列中已使用的长度
bool empty() const; //判断队列是否为空队列
void erase(); //清除队列中所有的数据
void print() const; //打印队列中的数据(该接口仅用来测试而已)
private:
T* m_pQueue;
UINT m_nHead; //记录队列头的位置
UINT m_nTail; //记录队列尾的位置
UINT m_nQueueLen; //队列已使用的长度
UINT m_nQueueSize; //队列总的长度
};
#endif //_ARR_QUEUE_H
1.2、实现方式
#include "ArrQueue.h"
#include <string.h>
#define INITQUEUELEN 5 //默认队列的长度
template<typename T>
ArrQueue<T>::ArrQueue(void)
{
m_nQueueSize = INITQUEUELEN;
m_pQueue = new T[m_nQueueSize];
m_nHead = 0;
m_nTail = 0;
m_nQueueLen = 0;
}
template<typename T>
ArrQueue<T>::ArrQueue(const UINT& InitSize):m_nQueueSize(InitSize)
{
m_pQueue = new T[m_nQueueSize];
m_nHead = 0;
m_nTail = 0;
m_nQueueLen = 0;
}
template<typename T>
ArrQueue<T>::~ArrQueue(void)
{
delete [] m_pQueue;
m_pQueue = NULL;
}
/****************************************!
*@brief 入队
*@author lyf
*@date 2019年4月1日 21:12
*@param[out]
*@param[in] const T & data
*@return bool
****************************************/
template<typename T>
bool ArrQueue<T>::enqueue(const T& data)
{
if(!m_pQueue || (m_nTail == m_nQueueSize && m_nHead == 0)) //如果队列满了或者空间的地址无效
return false;
else if(m_nTail < m_nQueueSize)
{
m_pQueue[m_nTail++] = data;
++m_nQueueLen;
return true;
}
else
{
//memcpy(m_pQueue, &m_pQueue[m_nHead], sizeof(T) * m_nQueueLen);//目标位置与源位置存在重叠
for(UINT i = 0; i < m_nQueueLen; ++i)
{
m_pQueue[i] = m_pQueue[m_nHead++];
}
m_nHead = 0;
m_pQueue[m_nQueueLen++] = data;
m_nTail = m_nQueueLen;
return true;
}
}
/****************************************!
*@brief 出队
*@author lyf
*@date 2019年4月1日 21:17
*@param[out]
*@return bool
****************************************/
template<typename T>
bool ArrQueue<T>::dequeue()
{
if(m_nQueueLen == 0) //队列为空时
return false;
else
{
m_nHead += 1;
--m_nQueueLen;
return true;
}
}
/****************************************!
*@brief 获取队列有效长度
*@author lyf
*@date 2019年4月1日 21:31
*@param[out]
*@return UINT
****************************************/
template<typename T>
UINT ArrQueue<T>::getlength() const
{
return m_nQueueLen;
}
/****************************************!
*@brief 判断队列是否为空
*@author lyf
*@date 2019年4月1日 21:32
*@param[out]
*@return bool
****************************************/
template<typename T>
bool ArrQueue<T>::empty() const
{
return m_nQueueLen == 0;
}
/****************************************!
*@brief 清空队列
*@author lyf
*@date 2019年4月1日 21:32
*@param[out]
*@return void
****************************************/
template<typename T>
void ArrQueue<T>::erase()
{
m_nHead = 0;
m_nTail = 0;
m_nQueueLen = 0;
}
/****************************************!
*@brief 打印队列中的数据
*@author lyf
*@date 2019年4月1日 21:48
*@param[out]
*@return void
****************************************/
template<typename T>
void ArrQueue<T>::print() const
{
if(empty())
std::cout << "Current queue is empty!" << std::endl;
else
{
int index = m_nHead;
int i = 1;
while(index != m_nTail)
{
std::cout << "The " << i << "th element data is " << m_pQueue[index++] << std::endl;
}
std::cout << "All elements are printed." << std::endl;
}
}
2、链式队列
由于接口定义与顺序队列类似就不在此赘述,下面直接给出实现方式。
2.1、实现方式
#include "ListQueue.h"
template<typename T>
ListQueue<T>::ListQueue(void)
{
m_pHead = m_pTail = NULL;
m_QueueLen = 0;
}
template<typename T>
ListQueue<T>::~ListQueue(void)
{
erase();
}
/****************************************!
*@brief 入队(入队更新尾)
*@author lyf
*@date 2019年3月31日 23:06
*@param[out]
*@param[in] const T & data
*@return bool
****************************************/
template<typename T>
bool ListQueue<T>::enqueue(const T& data)
{
QueueNode pNewNode = new SNode<T>;
if(pNewNode == NULL)
return false;
else
{
pNewNode->data = data;
pNewNode->pNext = NULL;
if(m_pHead == NULL)
{
m_pHead = pNewNode;
m_pTail = pNewNode;
}
else
{
m_pTail->pNext = pNewNode;
m_pTail = pNewNode;
}
++m_QueueLen;
return true;
}
}
/****************************************!
*@brief 出队(出队更新头)
*@author lyf
*@date 2019年3月31日 23:06
*@param[out]
*@return bool
****************************************/
template<typename T>
bool ListQueue<T>::dequeue()
{
if(m_QueueLen == 0)
return false;
else
{
QueueNode TempNode = m_pHead->pNext;
delete m_pHead;
m_pHead = TempNode;
--m_QueueLen;
return true;
}
}
/****************************************!
*@brief
*@author lyf
*@date 2019年3月31日 22:47
*@param[out]
*@return void
****************************************/
template<typename T>
void ListQueue<T>::print() const
{
if(m_QueueLen == 0)
std::cout << "Current queue is empty!" << std::endl;
else
{
QueueNode TempNode = m_pHead;
UINT i = 1;
while(TempNode)
{
std::cout << "The " << i << "th element data is " << TempNode->data << std::endl;
++i;
TempNode = TempNode->pNext;
}
std::cout << "All elements are printed." << std::endl;
}
}
/****************************************!
*@brief
*@author lyf
*@date 2019年3月31日 22:47
*@param[out]
*@return UINT
****************************************/
template<typename T>
UINT ListQueue<T>::getlength() const
{
return m_QueueLen;
}
/****************************************!
*@brief
*@author lyf
*@date 2019年3月31日 22:47
*@param[out]
*@return bool
****************************************/
template<typename T>
bool ListQueue<T>::empty() const
{
return m_QueueLen == 0;
}
/****************************************!
*@brief
*@author lyf
*@date 2019年3月31日 22:47
*@param[out]
*@return void
****************************************/
template<typename T>
void ListQueue<T>::erase()
{
while(!empty())
{
dequeue();
}
m_pHead = m_pTail = NULL;
}
3、循环队列
同样接口定义与顺序队列类似,因此不过多赘述。
3.1、实现方式
#include "CircleQueue.h"
#define INITQUEUELEN 5
template<typename T>
CircleQueue<T>::CircleQueue(void)
{
m_nQueueSize = INITQUEUELEN;
m_pQueue = new T[m_nQueueSize];
m_nHead = 0;
m_nTail = 0;
m_nQueueLen = 0;
}
template<typename T>
CircleQueue<T>::~CircleQueue(void)
{
delete []m_pQueue;
m_pQueue = NULL;
}
template<typename T>
CircleQueue<T>::CircleQueue(const UINT &InitSize):m_nQueueSize(InitSize)
{
m_pQueue = new T[m_nQueueSize];
m_nHead = 0;
m_nTail = 0;
m_nQueueLen = 0;
}
/****************************************!
*@brief 入队
*@author lyf
*@date 2019年4月2日 23:49
*@param[out]
*@param[in] const T & data
*@return bool
****************************************/
template<typename T>
bool CircleQueue<T>::enqueue(const T& data)
{
if((m_nTail + 1) % m_nQueueSize == m_nHead) //判断队列是否已满
return false;
else
{
m_pQueue[m_nTail] = data;
m_nTail = (m_nTail + 1) % m_nQueueSize; //注意队列尾位置的更新方式
++m_nQueueLen;
return true;
}
}
/****************************************!
*@brief 出队
*@author lyf
*@date 2019年4月2日 23:53
*@param[out]
*@return bool
****************************************/
template<typename T>
bool CircleQueue<T>::dequeue()
{
if(m_nHead == m_nTail) //判断队列是否为空
return false;
else
{
m_nHead = (m_nHead + 1) / m_nQueueSize; //注意队列头位置的更新方式
--m_nQueueLen;
return true;
}
}
/****************************************!
*@brief 获取队列中有效数据的长度
*@author lyf
*@date 2019年4月2日 23:54
*@param[out]
*@return UINT
****************************************/
template<typename T>
UINT CircleQueue<T>::getlength() const
{
return m_nQueueLen;
}
/****************************************!
*@brief
*@author lyf
*@date 2019年4月2日 23:54
*@param[out]
*@return bool
****************************************/
template<typename T>
bool CircleQueue<T>::empty() const
{
return m_nHead == m_nTail; //m_nQueueLen == 0;
}
/****************************************!
*@brief 清空队列
*@author lyf
*@date 2019年4月2日 23:55
*@param[out]
*@return void
****************************************/
template<typename T>
void CircleQueue<T>::erase()
{
m_nHead = 0;
m_nTail = 0;
m_nQueueLen = 0;
}
/****************************************!
*@brief 打印队列中的有效数据
*@author lyf
*@date 2019年4月2日 23:56
*@param[out]
*@return void
****************************************/
template<typename T>
void CircleQueue<T>::print() const
{
if(empty())
std::cout << "Current queue is empty!" << std::endl;
else
{
UINT index = m_nHead;
int i = 1;
while(index != m_nTail)
{
std::cout << "The " << i << "th element data is " << m_pQueue[index] << std::endl;
index = (index + 1) / m_nQueueSize; //索引需要通过对模取余的方式确定
++i;
}
std::cout << "All elements are printed." << std::endl;
}
}