队列和上篇提到的栈类似,本质上都是特殊的线性表,它是在一端(队头)进行删除操作,另一端(队尾)进行插入操作,遵守先进先出的规则。。
既然队列也是线性表,当然也有两种数据存储方式:
顺序存储结构:这种结构事先要基本确定队列的大小,不支持动态分配存储空间,所以插入和删除元素比较省时,但是会造成空间的浪费。
为了节省空间,这里引入了循环队列,本质上也是顺序存储结构。
链式存储结构:可以不需要事先知道队列的大小,支持动态和释放空间,但是插入和删除操作比较耗时,也称链队列。
建议:当事先基本上确定队列的大小,且插入和删除操作比较频繁时,优先考虑循环队列。。
1.循环队列实现:
头文件声明和定义放一块了,只实现了基本的操作,不是很完善,等看了源码再改。。
头文件:在Queue.h头文件中
#ifndef QUEUE_H #define QUEUE_H #include<cassert> #include<iostream> using namespace std; template<typename T> class Queue { public: Queue(int maxsize = 10); Queue(const Queue<T>& rhs); Queue<T>& operator=(const Queue<T>& rhs); ~Queue(); public: bool empty() const; bool IsFull() const; int size() const; void push(const T& data); void pop(); T& front(); T front() const; T& back(); T back() const; private: T *array; int Front; int rear; int capacity; }; template<typename T> Queue<T>::Queue(int maxsize) :Front(0), rear(0),capacity(maxsize) { array = new T[maxsize]; assert(array != NULL); //存储分配失败则退出; } template<typename T> Queue<T>::Queue(const Queue<T>& rhs) :Front(rhs.Front), rear(rhs.rear),capacity(rhs.capacity) { array = new T[capacity]; for (int i = 0; i != (this->size()); i++) array[i] = rhs.array[i]; } template<typename T> Queue<T>& Queue<T>::operator=(const Queue<T>& rhs) { if (this != &rhs) { delete[] array; capacity = rhs.capacity; Front = rhs.Front; rear = rhs.rear; array = new T[capacity]; for (int i = 0; i != (this->size()); i++) array[i] = rhs.array[i]; } return *this; } template<typename T> Queue<T>::~Queue() { delete[] array; } template<typename T> bool Queue<T>::empty() const { return Front == rear; //此处为循环队列,当front==rear时为空。 } template<typename T> bool Queue<T>::IsFull() const { return(rear + 1) % capacity == Front; //当(rear+1)%capacity==front为满,因为为满时差一个元素,但是可能rear>front,也可能rear<front. } template<typename T> int Queue<T>::size() const { return (rear - Front + capacity) % capacity; } template<typename T> void Queue<T>::push(const T& data) { if (!IsFull()) { array[rear] = data; rear = (rear + 1) % capacity; } else //当队列满了之后可进行扩容 { T *newarray=new T[ 2*capacity ]; for (int i = 0; i != 2*capacity&&!this->empty(); i++) { newarray[i] =this-> front(); this->pop(); } delete [ ] array; array = newarray; Front = 0; array[rear] = data; rear =this->rear+1; capacity = 2*capacity; } } template<typename T> void Queue<T>::pop() { if (!empty()) { //array[Front].~T(); //将队头元素析构掉 Front = (Front + 1) % capacity; } else cout<<"empty queue!"<<endl; } template<typename T> T& Queue<T>::front() { if (empty()) cerr << "Error, queue is empty!"; return array[Front]; } template<typename T> T Queue<T>::front() const { if (empty()) cerr << "Error, queue is empty!"; return array[Front]; } template<typename T> T& Queue<T>::back() { if (empty()) cerr << "Error, queue is empty!"; return array[rear-1]; //rear类似与尾后指针 } template<typename T> T Queue<T>::back() const { if (empty()) cerr << "Error, queue is empty!"; return array[rear-1]; } #endif // QUEUE_H
测试代码:
网上找的代码:
#include<iostream> #include"Queue.h" using namespace std; int main() { Queue<int> q(10); //声明队列 int n; cin >> n; for (int i = 0; i<n; i++) q.push(i + 1); while (!q.empty()) { cout << q.front() << " "; q.pop(); if (!q.empty()) //此处需要判断此时队列是否为空 { q.push(q.front()); q.pop(); } } cout << endl; return 0; }
2.链队列的实现:
头文件:
在Queue1.h头文件中
#ifndef QUEUE_H1 #define QUEUE_H1 /**********在队头删除节点,队尾添加节点*************/ #include<iostream> using namespace std; template<typename T> class Queue { public: Queue(); ~Queue(); bool empty() const; int size() const; void clear(); void push(const T & node); void pop(); T& front(); T front() const; private: //也可以直接用来链表list直接构造 struct QueueNode { T data; QueueNode* next; QueueNode(const T& Newdata, QueueNode* nextnode=NULL) :data(Newdata), next(nextnode) { } // QueueNode() = default; }; QueueNode * Front; //队头指针 QueueNode * rear; // 队尾指针 int count; }; //此处不设头节点 template<typename T> Queue<T>::Queue() :Front (NULL), rear (NULL), count(0) {} template<typename T> Queue<T>::~Queue() { clear(); } template<typename T> void Queue<T>::push(const T & node) { if(Front==NULL) Front=rear=new QueueNode(node); else { QueueNode * newqueuenode = new QueueNode(node); rear->next = newqueuenode; rear = newqueuenode; } count++; } template<typename T> bool Queue<T>::empty() const { return Front==NULL; } template<typename T> int Queue<T>::size() const { return count; } template<typename T> void Queue<T>::clear() { while (Front) { QueueNode * FrontofQueue = Front; Front = Front->next; delete FrontofQueue; } count = 0; } template<typename T> void Queue<T>::pop() { if (empty()) { cerr << "Error, queue is empty!"; } QueueNode * FrontofQueue = Front; Front = Front->next; delete FrontofQueue; count--; } template<typename T> T& Queue<T>::front() { if (empty()) { cerr << "Error, queue is empty!"; } return Front->data; } template<typename T> T Queue<T>::front() const { if (empty()) { cerr << "Error, queue is empty!"; } return Front->data; } #endif // QUEUE_H1
测试代码:
#include<iostream> #include"Queue1.h" using namespace std; int main() { Queue<int> q; //声明队列 int n; cin >> n; for (int i = 0; i<n; i++) q.push(i + 1); while (!q.empty()) { cout << q.front() << " "; q.pop(); if (!q.empty()) //此处需要判断此时队列是否为空 { q.push(q.front()); q.pop(); } } cout << endl; return 0; }
两种方法运行结果是一样的。。