隊列和上篇提到的棧類似,本質上都是特殊的線性表,它是在一端(隊頭)進行刪除操作,另一端(隊尾)進行插入操作,遵守先進先出的規則。。
既然隊列也是線性表,當然也有兩種數據存儲方式:
順序存儲結構:這種結構事先要基本確定隊列的大小,不支持動態分配存儲空間,所以插入和刪除元素比較省時,但是會造成空間的浪費。
為了節省空間,這里引入了循環隊列,本質上也是順序存儲結構。
鏈式存儲結構:可以不需要事先知道隊列的大小,支持動態和釋放空間,但是插入和刪除操作比較耗時,也稱鏈隊列。
建議:當事先基本上確定隊列的大小,且插入和刪除操作比較頻繁時,優先考慮循環隊列。。
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; }
兩種方法運行結果是一樣的。。