队列是一种操作受限的线性表。在这种线性表上,插入操作限定在表的某一端进行,删除限定在表的另一端进行。允许插入的一端为队尾,允许删除的一端为对头。队列按照存储方式分为两种,分别是顺序存储和链式存储。其中顺序存储方式的队列为循环队列。
废话不多说,直接上代码,下面是是我简单实现的队列的两种模式,顺序和链式,采用C++语言,在Qt5.9.0下编译成功。
#include "queue.h"
#ifndef QUEUE_H
#define QUEUE_H#include <iostream>#define MaxSize 100
#define ERROR 0
#define OK 1
typedef int size_type;
typedef unsigned status_type;template <class QElemType>
class Queue
{template<class T>friend std::ostream &operator<<(std::ostream &output, const Queue<T> &Q);
public:Queue();//构造函数Queue(size_type size);Queue(const Queue<QElemType> &Q);//拷贝构造~Queue();status_type EnQueue(QElemType x);//入队status_type Full();//判断队列是否已满status_type Empty();//判空函数size_type Size() const;status_type OutQueue(QElemType *x);//出队status_type GetHeadQueue(QElemType *x);//取队头QElemType Front()const;QElemType& Front();Queue<QElemType>& operator=(const Queue<QElemType> &Q);private:QElemType *m_Data;size_type m_Front;size_type m_Rear;size_type m_size;
};#endif // QUEUE_H
#include "queue.cpp"
#include "queue.h"
#include <cassert>template <class QElemType>
Queue<QElemType>::Queue():m_Front(0),m_Rear(0),m_size(MaxSize + 1)
{m_Data = new QElemType[MaxSize + 1];assert(m_Data != NULL);
}template <class QElemType>
Queue<QElemType>::Queue(size_type size):m_Front(0),m_Rear(0),m_size(size + 1)
{m_Data = new QElemType[size + 1];assert(m_Data != NULL);
}template <class QElemType>
Queue<QElemType>::Queue(const Queue<QElemType> &Q):m_Front(Q.m_Front),m_Rear(Q.m_Rear),m_size(Q.m_size)
{m_Data = new QElemType[m_size];assert(m_Data != NULL);for (int i = 0; i < Q.Size(); i++){m_Data[(m_Front + i + 1) % m_size] = Q.m_Data[(Q.m_Front + i + 1) % Q.m_size];}
}template <class QElemType>
Queue<QElemType>::~Queue()
{delete []m_Data;
}template<class QElemType>
Queue<QElemType>& Queue<QElemType>::operator=(const Queue<QElemType> &Q)
{if (this != &Q){delete []m_Data;m_Front = Q.m_Front;m_Rear = Q.m_Rear;m_size = Q.m_size;m_Data = new QElemType[m_size];if (!m_Data){std::cerr << "Error:Malloc faiure!" << std::endl;return *this;}for(int i = 0; i < Q.Size(); i++){m_Data[(m_Front + i + 1) % m_size] = Q.m_Data[(m_Front + i + 1) % m_size];}}return *this;
}template <class QElemType>
status_type Queue<QElemType>::EnQueue(QElemType x)
{if (Full()){QElemType *newData = new QElemType[2*m_size];if (!newData){std::cerr <<"Error:Queue is full,out of memory!" << std::endl;return ERROR;}for (int i = 0; i != 2*m_size && !Empty(); i++){OutQueue(newData + m_Front + 1);}delete []m_Data;m_Data = newData;m_size = 2*m_size;m_Front = 0;m_Rear = (m_Rear + 1) % m_size;m_Data[m_Rear] = x;return OK;}m_Rear = (m_Rear + 1) % m_size;m_Data[m_Rear] = x;return OK;
}template <class QElemType>
status_type Queue<QElemType>::OutQueue(QElemType *x)
{if (Empty()){std::cerr << "Error:Queue is free!" << std::endl;return ERROR;}m_Front = (m_Front + 1) % m_size;*x = m_Data[m_Front];return OK;
}template <class QElemType>
status_type Queue<QElemType>::GetHeadQueue(QElemType *x)
{if (Empty()){std::cerr << "Error:Queue is free!" << std::endl;return ERROR;}*x = m_Data[(m_Front + 1) % m_size];return OK;
}template <class QElemType>
status_type Queue<QElemType>::Empty()
{return m_Rear == m_Front;
}template <class QElemType>
status_type Queue<QElemType>::Full()
{return (m_Rear + 1) % m_size == m_Front;
}template <class QElemType>
size_type Queue<QElemType>::Size()const
{return (m_Rear - m_Front + m_size) % m_size;
}template <class QElemType>
QElemType Queue<QElemType>::Front()const
{if (Empty()){std::cerr << "Error:Queue is empty!" << std::endl;assert(!Empty());}return m_Data[m_Front + 1];
}template <class QElemType>
QElemType& Queue<QElemType>::Front()
{if (Empty()){std::cerr << "Error:Queue is empty!" << std::endl;assert(!Empty());}return m_Data[m_Front + 1];
}template<class T>
std::ostream &operator<<(std::ostream& output, const Queue<T> &Q)
{size_type front = Q.m_Front;output << "Queue element is:" << std::endl;while (front != Q.m_Rear) {output << Q.m_Data[++front % Q.m_size] << " ";}return output;
}
上面的代码是采用顺序存储方式实现的队列,默认数组第一个元素不存储数据,队列的最大存储容量为MaxSize - 1,所以构造函数中,对成员变量m_size的初始化需要做MaxSize + 1的操作。但是在EnQueue()函数中做了一个扩容的操作,所以实际的存储容量是不固定的。
/*
这部分代码是对队列的一个扩容的操作
*/
QElemType *newData = new QElemType[2*m_size]; if (!newData) { std::cerr <<"Error:Queue is full,out of memory!" << std::endl; return ERROR; }
for (int i = 0; i != 2*m_size && !Empty(); i++) { OutQueue(newData + m_Front + 1); } delete []m_Data; m_Data = newData; m_size = 2*m_size; m_Front = 0; m_Rear = (m_Rear + 1) % m_size; m_Data[m_Rear] = x;
下面是链式存储队列:
#include "linkqueue.h
#ifndef LINKQUEUE_H
#define LINKQUEUE_H#include <iostream>#define ERROR 0
#define OK 1
typedef int status_t;
typedef unsigned size_t;template<class LQElemType>
class LinkQueue
{
private:typedef struct QNode{LQElemType data;struct QNode *next;QNode():next(NULL){}QNode(const LQElemType& newData, QNode* newNext = NULL):data(newData),next(newNext){}}QNode, *QueuePtr;public:LinkQueue();//构造函数LinkQueue(const LinkQueue<LQElemType>& LQ);//拷贝构造~LinkQueue();status_t EnQueue(LQElemType e);//入队status_t OutQueue(LQElemType *e);//出队status_t GetHeadQueue(LQElemType *e);//取队头status_t Empty()const;//判空函数size_t Size()const;void Clear();//清除队列LQElemType Front()const;LQElemType& Front();LinkQueue<LQElemType>& operator = (const LinkQueue<LQElemType>& LQ);template<class T>friend std::ostream& operator << (std::ostream& output, const LinkQueue<T>& LQ);private:QueuePtr m_Front;QueuePtr m_Rear;size_t count;
};#endif // LINKQUEUE_H
#include "linkqueue.cpp"
"
#include "linkqueue.h"
#include <cassert>template<class LQElemType>
LinkQueue<LQElemType>::LinkQueue():count(0)
{QueuePtr pQ = new QNode();assert(pQ != NULL);m_Front = m_Rear = pQ;
}template<class LQElemType>
LinkQueue<LQElemType>::LinkQueue(const LinkQueue<LQElemType> &LQ):count(LQ.count)
{QueuePtr pQ = new QNode();assert(pQ != NULL);m_Front = m_Rear = pQ;QueuePtr p = LQ.m_Front->next;while (p) {if (EnQueue(p->data))p = p->next;}
}template<class LQElemType>
LinkQueue<LQElemType>::~LinkQueue()
{delete m_Front;delete m_Rear;
}template<class LQElemType>
status_t LinkQueue<LQElemType>::EnQueue(LQElemType e)
{QueuePtr pQ = new QNode(e);if (!pQ){std::cerr << "Error:Malloc faiure!" << std::endl;return ERROR;}count++;m_Rear->next = pQ;m_Rear = pQ;return OK;
}template<class LQElemType>
status_t LinkQueue<LQElemType>::OutQueue(LQElemType *e)
{QueuePtr pQ;if (Empty()){std::cerr << "Error:Queue is empty!" << std::endl;return ERROR;}count--;*e = m_Front->next->data;pQ = m_Front->next;m_Front->next = pQ->next;if (m_Front->next == NULL){m_Rear = m_Front;}delete pQ;return OK;
}template<class LQElemType>
status_t LinkQueue<LQElemType>::GetHeadQueue(LQElemType *e)
{if (Empty()){std::cerr << "Error:Queue is empty!" << std::endl;return ERROR;}*e = m_Front->next->data;return OK;
}template<class LQElemType>
status_t LinkQueue<LQElemType>::Empty() const
{return m_Front->next == NULL;
}template<class LQElemType>
size_t LinkQueue<LQElemType>::Size() const
{return count;
}template<class LQElemType>
void LinkQueue<LQElemType>::Clear()
{while (m_Front->next) {QueuePtr p = m_Front->next;m_Front->next = p->next;delete p;}m_Rear = m_Front;count = 0;
}template<class LQElemType>
LQElemType LinkQueue<LQElemType>::Front()const
{if (Empty()){std::cerr << "Error:Queue is empty!" << std::endl;assert(!Empty());}return m_Front->next->data;
}template<class LQElemType>
LQElemType& LinkQueue<LQElemType>::Front()
{if (Empty()){std::cerr << "Error:Queue is empty!" << std::endl;assert(!Empty());}return m_Front->next->data;
}template<class LQElemType>
LinkQueue<LQElemType>& LinkQueue<LQElemType>::operator = (const LinkQueue<LQElemType>& LQ)
{if (this != &LQ){Clear();QueuePtr p = LQ.m_Front->next;while (p) {if (EnQueue(p->data))p = p->next;}count = LQ.count;}return *this;
}template<class T>
std::ostream& operator << (std::ostream& output, const LinkQueue<T>& LQ)
{auto p = LQ.m_Front->next;output << "Link queue element is:" << std::endl;while (p) {output << p->data << " ";p = p->next;}return output;
}
在链式队列中,对头指针m_Front指向第一个结点,通俗讲就是对头指针m_Front就是第一个结点,而且默认第一个结点是不存储数据的;队尾指针m_Rear指向最后一个结点,当m_Front和m_Rear指向同一个结点时,队列为空。next指针存放下一个结点的地址,当m_Front->next != NULL时,队列一定不为空,而且任何时候m_Rear->next == NULL都成立。
测试代码:
#include <iostream>
#include "queue.cpp"
#include "linkqueue.cpp"using namespace std;int main()
{//C++实现循环队列cout << "C++实现循环队列" << endl;Queue<int> q(20);LinkQueue<int> lq;for (int i = 0; i < 30; i++){q.EnQueue(i + 1);lq.EnQueue(i * 10);}cout << q << endl;Queue<int> q2;q2 = q;cout << q2 << endl;Queue<int> q3 = q2;cout << q3 << endl;cout << lq << endl;LinkQueue<int> lq2;LinkQueue<int> lq3 = lq;lq2 = lq;cout << lq2 << endl;cout << lq3 << endl;LinkQueue<int> lq4;return 0;
}
上面是是我花了一点时间实现的队列,有错的地方或者不完善的地方,欢迎吐槽并指正