数据结构之队列queue
C++數(shù)據(jù)結(jié)構(gòu)之隊列queue
什么是隊列
隊列的基本特征
隊列是如何工作的
隊列的實現(xiàn)
隊列的應(yīng)用
什么是隊列
與棧相反,隊列是一種先進(jìn)先出(FIFO)的線性表,只允許在表的一端插入,在另一端刪除。允許插入的一端叫隊尾,允許刪除 的一端叫隊頭。比較典型的例子有日常生活中的排隊:銀行排序辦理業(yè)務(wù)、地鐵排隊上車(emmmm,這里假設(shè)所有人都遵守秩序)等,當(dāng)然還有計算機(jī)系統(tǒng)的消息隊列,操作系統(tǒng)的作業(yè)調(diào)度(這兩者都可以看做是隊列,不過是隊列的高級應(yīng)用:優(yōu)先級隊列)等
隊列的基本特征
- 先進(jìn)先出(FIFO) - 限制插入和刪除:隊尾(back)插入,隊頭(front)刪除隊列是如何工作的
如下圖所示:
front代表隊頭,back代表隊尾,初始狀態(tài),front與back指向同一位置,當(dāng)插入一個新元素a后,隊尾back向后移動一位,隊頭front不動,指向下一個位置,當(dāng)在a的下一個位置插入元素b時,隊尾back繼續(xù)向后移動一位,直到滿隊列,此時back指向最后的位置。當(dāng)刪除一個元素時,隊頭front向后移動一位,隊尾back不動。在這種隊列結(jié)構(gòu)下,可以通過(front == back)來判斷隊列是否為空。
隊列的實現(xiàn)
隊列的實現(xiàn)主要有兩種方式:順序表和鏈表;隊列的操作主要有:取出隊頭元素(front())、 刪除隊頭元素(pop())、隊尾插入元素(push())、是否為空(Empty())、隊列元素數(shù)(size()) 、是否已滿(Full())順序表實現(xiàn)隊列
順序表的實現(xiàn)較為簡單,直接使用數(shù)據(jù)存儲數(shù)據(jù)即可,而front和back代表數(shù)組的下標(biāo)(索引), 這樣做的缺點就是隊列的長度固定,同時由于每次刪除元素時,隊頭向后移動一位,當(dāng)隊列中所有 元素被刪除時,此時front ==back,但是,此時繼續(xù)向隊列中插入元素時,就會出現(xiàn)數(shù)組越界的 情況。 如上所示,此時,front與back都以指向了最后位置,無法繼續(xù)在隊列中插入數(shù),但是, front前面的空間仍舊是空的,沒有存儲內(nèi)容,此時如果采用動態(tài)內(nèi)存分配無疑會浪費內(nèi) 存空間,因此,為了能夠充分利用已分配的數(shù)組空間,可以將數(shù)組想象為一個首尾相 接的環(huán),循環(huán)存儲數(shù)據(jù),稱之為循環(huán)隊列。 如上,將數(shù)組想象成環(huán)狀,初始時,front與back都指向起始位置,當(dāng)有元素插入或者刪除時, 進(jìn)行相應(yīng)的移動,直到back的下一個位置為front時,隊列為滿。由于是環(huán)狀的,因此, front與back的代表的位置應(yīng)該對隊列的長度取余后,才為數(shù)組的下標(biāo)。同時,為了便于判斷 隊列為滿和隊列為空,在設(shè)置隊列長度時,應(yīng)該為length+1,因為back始終指向隊尾元素的 下一個位置,所以,當(dāng)隊列滿時,back應(yīng)該指向隊列長度的下一個位置,從而,可以通過 (back+1)%(length+1) == front判斷隊列滿,通過back==front判斷隊列為空。代碼實現(xiàn)
//頭文件定義 template <typename T> class Queue { public:Queue(int max_size);virtual ~Queue();T & Front() const;void Pop();void Push(T &element);bool Empty() const;int size() const;bool Full() const; private:int front_;int back_;int size_;int max_size_;T *contain; //隊列指針};//代碼實現(xiàn) #include "Queue.h" #include <iostream> #include <assert.h> ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// template <typename T> Queue<T>::Queue(int max_size) {front_ = back_ = 0;size_ = 0;max_size_ = max_size + 1;contain = new T[max_size_]; //比隊列長度多一個元素,用于輔助存放back_以及判斷滿 }template <typename T> Queue<T>::~Queue() {delete [] contain; }template <typename T> bool Queue<T>::Empty() const {return front_ == back_; //指向同一位置 }template <typename T> T & Queue<T>::Front() const {assert(!Empty()); //斷言不為空,為空則程序直接報出異常中止return contain[front_]; }template <typename T> bool Queue<T>::Full() const {return (back_ + 1) % max_size_ == front_; //由于是環(huán)狀所以對最大長度取余 }template <typename T> void Queue<T>::Pop() {front_ = (front_ + 1) % max_size_;size_--; }template <typename T> void Queue<T>::Push(T &element) {assert(!Full());contain[back_] = element;back_ = (back_ + 1) % max_size_;size_++; }template <typename T> int Queue<T>::size() const {return size_; }鏈表實現(xiàn)隊列
用鏈表來實現(xiàn)隊列更符合隊列的特征,不需要進(jìn)行循環(huán),刪除隊頭元素直接釋放隊頭元素 空間即可,插入隊尾時,直接新增空間即可添加,同時隊尾指針指向隊尾元素,不再指向 下一節(jié)點,如下圖所示。 與鏈表不同的是,鏈表有頭結(jié)點,而隊列不需要頭結(jié)點,空隊列時,隊頭指針與隊尾指針 都指向NULL,同時此時判斷隊列滿也沒有什么意義。因而用鏈表實現(xiàn)隊列的功能有取頭 節(jié)點(Front())、刪除頭節(jié)點(Pop())、插入新元素(Push())、是否為空(Empty()) 、隊列中元素個數(shù)(size())代碼實現(xiàn)
//頭文件定義 template <typename T> //節(jié)點 struct ListNode{T data;ListNode<T> *link; }; //鏈表類 template <typename T> class ListQueue { public:ListQueue();virtual ~ListQueue();T & front() const;void Pop();void Push(T &element);bool Empty() const;int size() const; private:int size_;ListNode<T> *front_;ListNode<T> *back_; };//cpp實現(xiàn) #include "ListQueue.h" #include <iostream> #include <assert.h>////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// template <typename T> ListQueue<T>::ListQueue() {front_ = back_ = NULL;size_ = 0; }template <typename T> ListQueue<T>::~ListQueue() {while (!Empty()) {this->Pop();} }template <typename T> bool ListQueue<T>::Empty() const {return front_ == NULL; }template <typename T> T & ListQueue<T>::front() const{assert(!Empty());return front_->data; }template <typename T> void ListQueue<T>::Pop() {assert(!Empty());ListNode<T> *temp = front_;front_ = front_->link;delete temp;size_--; }template <typename T> void ListQueue<T>::Push(T &element) {ListNode<T> *new_node= new ListNode<T>;new_node->data = element;new_node->link = NULL;if (back_ == NULL) {front_ = back_ = new_node;} else {back_->link = new_node;back_ = back_->link;}size_++; }template <typename T> int ListQueue<T>::size() const {return size_; }隊列的應(yīng)用
編程練習(xí)之隊列篇:舞伴問題
編程練習(xí)之隊列篇:游程編碼問題
編程練習(xí)之隊列篇:楊輝三角問題
編程練習(xí)之隊列篇:優(yōu)先級隊列
未完待續(xù)
以上是我關(guān)于隊列的學(xué)習(xí)心得,如果有什么不對的地方,歡迎大家指出,一起交流討論
總結(jié)
以上是生活随笔為你收集整理的数据结构之队列queue的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 迅雷 linux 命令行 版本号,在Li
- 下一篇: 批处理事件查看器