隊列簡介
如圖是含有n個元素的隊列的模型。根據隊列的出入元素特點,可以確定,元素a1最先入隊,緊接着a2,s3 ... 如果a2要出隊,必須等a1出隊。a1最先入隊,也是最先出隊,an最后入隊,也是最后出隊。
鏈式隊列
鏈式隊列是隊列的實現方式之一。鏈式隊列內部使用帶頭結點的單向鏈表來實現。它的好處的是靈活,隊列容量理論上是不受限制的。
我們使用鏈表的首結點來表示隊列的隊頭,鏈表的尾結點代表隊尾。
當隊列為空時,隊尾元素指針指向頭結點headNode。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cassert> #define NDEBUG struct Node{ int element; //結點保存的元素 Node*next; //next指針 Node(int e=0, Node*nxt=NULL):element(e),next(nxt) { } }; class LinkedQueue { private: Node headNode; //頭結點 ,headNode.next 就是隊頭結點的指針 Node* pRearNode; //表的最后一個結點的指針,隊尾結點的指針 int size; //隊列實際元素個數 public: LinkedQueue():headNode(),pRearNode(&headNode),size(0) { //初始化時, pRearNode 指向 headNode } ~LinkedQueue() { clear(); } void clear() { Node*p = headNode.next; Node*t; while(p!=NULL){ t = p; p=p->next; delete t; } //回歸初始狀態 headNode.next = NULL; pRearNode = &headNode; size=0; } bool isEmpty()const { #ifndef NDEBUG if(size==0){ //調試用 assert(pRearNode == &headNode); } #endif return (size==0 && pRearNode == &headNode ) ; } int length()const { return size; } //入隊 bool enQueue(int e) { Node*p_new = new Node(e,NULL); pRearNode->next = p_new; pRearNode = p_new; size++; } //出隊 bool deQueue() { if(isEmpty()) return false; //如果隊為空 Node*p_del = headNode.next; //獲取待刪結點的指針 headNode.next = (headNode.next)->next; //跳過,鏈接 //如果刪除的是最后一個結點。則應該重新賦值pRearNode,指向headNode if(pRearNode == p_del) pRearNode = &headNode; delete p_del; size--; } //獲取隊尾元素 bool getRear(int& e) const { if(!isEmpty()){ e = pRearNode->element; return true; } return false; } //獲取隊頭元素 bool getFront(int& e)const { if(!isEmpty()){ e = (headNode.next)->element; return true; } return false; } }; int main() { using namespace std; LinkedQueue queue; printf("length is :%d\n",queue.length()); printf("is empty? :%d\n",queue.isEmpty()); puts("\n----------put 10 elements to the queue-----------"); for(int i=0;i<10;++i){ queue.enQueue(i); } printf("length is :%d\n",queue.length()); printf("is empty? :%d\n",queue.isEmpty()); printf("--------pop 15 elements from the queue-------------\n"); for(int i=0,e;i<15;++i){ queue.getFront(e); if(queue.deQueue()) printf("%d ",e); } printf("\nlength is :%d\n",queue.length()); printf("is empty? :%d\n",queue.isEmpty()); return 0; }
循環隊列


具體實現要點
我們必須讓循環隊列的索引值限制在一定的范圍內(長度我n的數組的索引一定是0~n-1),而不是讓rear一直加1或者front一直減1。可以使用數學問題去解決:我們知道:將一個數M對n取模后,得到的結果將被映射到 0~n-1之間,循環隊列就是利用的這個特點來完成索引的變化的。
實現方式1
設一個變量size,保存隊列中元素的實際個數。每次出隊,size減1,入隊,size加1。而隊列的 空,滿,隊列長度都需要使用他來實現。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cassert> class CycleQueue { private: enum{QUEUE_CAPACITY = 10}; //內部常量,存儲循環隊列的最大容量 int*elements ; //存儲元素的數組 int front; //保存隊頭結點的索引 int rear; //保存下一個即將入隊元素在數組中的索引。 int size; //保存隊列的實際容量 public: CycleQueue() { elements = new int[QUEUE_CAPACITY]; front = rear=0; size =0; } ~CycleQueue() { delete[] elements; } void clear() { //回歸初始狀態 front = rear=0; size =0; } bool isEmpty()const { return size ==0; } bool isFull()const { return size == QUEUE_CAPACITY; } int length()const { return size; } //入隊 bool enQueue(int e) { if(isFull()) return false; elements[rear] = e; rear = (rear+1)%QUEUE_CAPACITY; size++; return true; } //出隊 bool deQueue() { if(isEmpty()) return false; front = (front+1)%QUEUE_CAPACITY; size --; return true; } //獲取隊尾元素 bool getRear(int& e) const { if(isEmpty()) return false; e= elements[rear-1]; return true; } //獲取隊頭元素 bool getFront(int& e)const { if(isEmpty()) return false; e= elements[front]; return true; } };
實現方式2
可以不使用size變量,另一種方法也可以實現隊列的 空,滿,隊列長度的獲取。即:讓隊列空出一個元素空間,我稱他為標記空間。因此數組長度為n的循環隊列,則只能存儲n-1個元素。
這個標記空間是循環隊列中隊尾元素邏輯上的后一個數組空間,但是這個空間在數組中的實際位置也是隨着出隊,入隊動態變化的。
ARRAY_CAPACITY是內部數組實際的容量,他的值是QUEUE_CAPACITY+1。因為隊列容器比數組容量少一。
空判斷:rear == front ? ”空“:"不為空"
滿判斷:(rear+1)%ARRAY_CAPACITY == front ? ”滿“:"不為滿"
實際元素個數:(rear - front + ARRAY_CAPACITY) % ARRAY_CAPACITY
#include<iostream> #include<cstdio> #include<cstdlib> #include<cassert> class CycleQueue { private: enum{QUEUE_CAPACITY=10}; //儲循環隊列的最大容量. enum{ARRAY_CAPACITY=QUEUE_CAPACITY+1}; //數組容量 int*elements ; //存儲元素的數組 int front; //保存隊頭結點的索引 int rear; //保存下一個即將入隊元素在數組中的索引。 public: CycleQueue() { elements = new int[ARRAY_CAPACITY]; front = rear=0; } ~CycleQueue() { delete[] elements; } void clear() { //回歸初始狀態 front = rear=0; } bool isEmpty()const { return front == rear; } bool isFull()const { return (rear+1)%ARRAY_CAPACITY == front; } int length()const { return (rear-front + ARRAY_CAPACITY)%ARRAY_CAPACITY; } //入隊 bool enQueue(int e) { if(isFull()) return false; elements[rear] = e; rear = (rear+1)%ARRAY_CAPACITY; return true; } //出隊 bool deQueue() { if(isEmpty()) return false; front = (front+1)%ARRAY_CAPACITY; return true; } //獲取隊尾元素 bool getRear(int& e) const { if(isEmpty()) return false; e= elements[rear-1]; return true; } //獲取隊頭元素 bool getFront(int& e)const { if(isEmpty()) return false; e= elements[front]; return true; } }; int main() { using namespace std; CycleQueue queue; printf("length is :%d\n",queue.length()); printf("is empty? :%d\n",queue.isEmpty()); puts("\n----------put 10 elements to the queue-----------"); for(int i=0;i<10;++i){ queue.enQueue(i); } printf("length is :%d\n",queue.length()); printf("is empty? :%d\n",queue.isEmpty()); printf("--------pop 5 elements from the queue-------------\n"); for(int i=0,e;i<5;++i){ queue.getFront(e); if(queue.deQueue()) printf("%d ",e); } printf("\nlength is :%d\n",queue.length()); printf("is empty? :%d\n",queue.isEmpty()); puts("\n----------put 2 elements to the queue-----------"); for(int i=0,e;i<2;++i){ queue.enQueue(i+100); } printf("\nlength is :%d\n",queue.length()); printf("is empty? :%d\n",queue.isEmpty()); printf("--------pop all elements from the queue-------------\n"); while(!queue.isEmpty() ){ int e; queue.getFront(e); if(queue.deQueue()) printf("%d ",e); } printf("\nlength is :%d\n",queue.length()); printf("is empty? :%d\n",queue.isEmpty()); return 0; }
雙端隊列
