数据结构——队列(顺序、链式、循环)

 队列是一种操作受限的线性表数据结构。对于它的操作需要遵守的规则是“先进者先出,后进者后出”,就像我们排队买票一样,排在队伍前边的先买到票先离开,排在队伍后边后买到票后离开,因此队列只支持两种操作,即入队和出队,其中入队是从队列的尾部插入新的元素,而出队则是在队列的头部弹出元素。由于该数据结构的特性,使其在实际中有很多的应用,比如消息队列、阻塞队列、并发队列等。

本文根据队列的基本特性实现了三种基本队列,分别是顺序队列,链式队列和循环队列。

完整实现详见于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;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值