环形队列出队的元素怎么输出出来_队列的知识讲解与基本实现(数据结构)
引言
中午在食堂打飯,真是一個(gè)令人頭疼的事情,去食堂的路上也總是步伐匆匆,為什么啊,這還用說,遲一點(diǎn)去,你就會(huì)知道什么叫做人山人海了,在食堂排隊(duì)的時(shí)候,相比較學(xué)生來說,打飯阿姨畢竟是少數(shù),在每個(gè)窗口都有人的時(shí)候,不免我們就得等待,直到前面的一個(gè)學(xué)生打完飯離開,后面排隊(duì)的人才可以繼續(xù)向前走,直到輪到自己,別提多費(fèi)勁了,但是秩序和規(guī)則卻是我們每個(gè)人都應(yīng)該遵守的,也只能抱怨自己來的遲了
這種 “先進(jìn)先出” 的例子就是我們所講的基本數(shù)據(jù)結(jié)構(gòu)之一 ”隊(duì)列“
例子補(bǔ)充:用電腦的時(shí)候,有時(shí)候機(jī)器會(huì)處于疑似死機(jī)的狀態(tài), 鼠標(biāo)點(diǎn)什么似乎都沒有用,雙擊任何快捷方式都不動(dòng),就當(dāng)你失去耐心,打算reset的時(shí)候,突然它就像酒醒了一樣,把你剛才點(diǎn)擊的所有操作全部按照順序執(zhí)行了一遍,這其實(shí)是因?yàn)椴僮飨到y(tǒng)中的多個(gè)程序隱需要通過一個(gè)通道輸出,而按照先后次序排隊(duì)等待造成的 ——《大話數(shù)據(jù)結(jié)構(gòu)》隊(duì)列的基本定義
定義:隊(duì)列是一種只允許在一段進(jìn)行刪除操作,在另一端進(jìn)行插入操作的線性表
允許插入的一段稱作隊(duì)尾 (rear),允許刪除的的一端稱為隊(duì)頭 (front)
隊(duì)列的數(shù)據(jù)元素又叫做隊(duì)列元素,在隊(duì)列中插入一個(gè)隊(duì)列元素稱為入隊(duì),從隊(duì)列中刪除一個(gè)隊(duì)列元素稱為出隊(duì) ,也正是因?yàn)殛?duì)列只允許在一段插入,另一端刪除,所以這也就是我們前面例子中體現(xiàn)出來的先進(jìn)先出 (FIFO-first in first out) 的概念
補(bǔ)充:除此之外,還有的隊(duì)列叫做雙端隊(duì)列,也就是可以在表的兩邊進(jìn)行插入和刪除操作的線性表雙端隊(duì)列分類:
隊(duì)列的抽象數(shù)據(jù)類型
#ifndef _QUEUE_H_#define _QUEUE_H_#include <exception>using namespace std;?// 用于檢查范圍的有效性class outOfRange:public exception { public: const char* what()const throw() { return "ERROR! OUT OF RANGE.n";} }; ?// 用于檢查長(zhǎng)度的有效性class badSize:public exception { public: const char* what()const throw() {return "ERROR! BAD SIZE.n";} }; ?template <class T>class Queue {public://判隊(duì)空 virtual bool empty() const = 0;//清空隊(duì)列 virtual void clear() = 0;//求隊(duì)列長(zhǎng)度 virtual int size() const = 0;//入隊(duì) virtual void enQueue(const T &x) = 0;//出隊(duì) virtual T deQueue() = 0;//讀隊(duì)頭元素 virtual T getHead() const = 0;//虛析構(gòu)函數(shù) virtual ~Queue(){} };#endif循環(huán)隊(duì)列
隊(duì)列作為一個(gè)特殊的線性表,自然也有著順序以及鏈?zhǔn)酱鎯?chǔ)兩種方式,我們先來看看它的順序存儲(chǔ)方式——循環(huán)隊(duì)列
在隊(duì)列的順序存儲(chǔ)中,我們除了創(chuàng)建一個(gè)具有一定空間的數(shù)組空間外,還需要兩個(gè)指針,分別指向隊(duì)列的前端和微端,下面的代碼中,我們選擇將隊(duì)頭指針指向頭元素的前一個(gè)位置,隊(duì)尾指針指向隊(duì)尾元素(當(dāng)然這不是唯一的方式,還可以將頭指針指向頭元素,隊(duì)尾指針指向隊(duì)尾元素的后一個(gè)位置,原理是基本一致的)
為什么要這么做,并且為什么這種存儲(chǔ)我們叫做循環(huán)隊(duì)列?
我們一步步分析一下:
我們先按照我們一般的想法畫出隊(duì)列元素進(jìn)出隊(duì)的過程,例如隊(duì)列元素出隊(duì)
這樣的設(shè)想,也就是根據(jù)我們前面食堂排隊(duì)的例子畫出來的,但是我們可以清晰的看到,當(dāng)a0出隊(duì)后,a0后的元素全部需要前移,將空位補(bǔ)上,但我們?cè)谟?jì)算機(jī)中講究性能二字,如何可以提高出隊(duì)的性能呢?
循環(huán)隊(duì)列就這樣被設(shè)計(jì)出來了,我們?nèi)绻辉傧拗脐?duì)頭一定在整個(gè)空間的最前面,我們的元素也就不需要集體移動(dòng)了
問題一
這個(gè)時(shí)候我們就需要考慮這樣的問題了:
① 如何為了解決只有一個(gè)元素的時(shí)候,隊(duì)頭和隊(duì)尾重合使得處理變得麻煩?
- 這時(shí)我們前面提到的兩個(gè)指針就派上用場(chǎng)了(隊(duì)頭指針指向頭元素的前一個(gè)位置,隊(duì)尾指針指向隊(duì)尾元素)當(dāng)頭尾指針相等的時(shí)候,代表是空隊(duì)列
問題二
但是有一個(gè)大問題出現(xiàn)了 !
如果前面有空閑的空間還好說,一旦頭元素前面沒有空間,我們的隊(duì)頭指針就指向到了數(shù)組之外,也就會(huì)出現(xiàn)數(shù)組越界問題,這該怎么辦呢?
我們可以看到,雖然我們的表頭已經(jīng)沒有了任何空間,但是表的后半部分還有空余空間,這種現(xiàn)象我們稱作假溢出,打個(gè)比方,接近上課你緩緩走進(jìn)教室,看到只有前排剩下了兩個(gè)位置,你總不會(huì)轉(zhuǎn)身就走吧,當(dāng)然可以去前排坐,只有實(shí)在沒座位了,才考慮離開
我們可以做出這樣一種比較可行的方案
- 我們只需要將這個(gè)隊(duì)列收尾連接起來,當(dāng)后面的空間滿后,接著從前面空出來的空間中進(jìn)隊(duì),同樣的,我們的表頭指針也找到了可以指向的位置
- 具體的連接方法,就是將date[0...maxSize] 的單元0認(rèn)為是maxSize - 1
問題三
我們剛才也提到了,當(dāng)表頭指針和表尾指針相等的時(shí)候就解決了空隊(duì)列的情況,但是在表滿的情況下,你會(huì)發(fā)現(xiàn),同樣也滿足表頭表尾指針相等,那么又如何解決這個(gè)問題呢?(我們給出三種可行的解決方案)
- A:設(shè)置一個(gè)標(biāo)志變量flag,當(dāng)front = rear的時(shí),且flag = 0的時(shí)候?yàn)榭?#xff0c;若flag = 1 的時(shí)候?yàn)殛?duì)列滿
- B:設(shè)計(jì)一個(gè)計(jì)數(shù)器count統(tǒng)計(jì)當(dāng)前隊(duì)列中的元素?cái)?shù)量,count == 0 隊(duì)列空,count == maxsSize 隊(duì)列滿
- C:保留一個(gè)存儲(chǔ)空間用于區(qū)分是否隊(duì)列已滿,也就是說,當(dāng)一個(gè)還空閑一個(gè)單元時(shí)候,我們就認(rèn)為表已經(jīng)滿了
我們重點(diǎn)講解 C 中的方法
我們根據(jù)這種方法可以總結(jié)出幾個(gè)條件的運(yùn)算式
- 隊(duì)列為滿的條件:(rear+1) % MaxSize == front
- 隊(duì)列為空的條件:front == rear
- 隊(duì)列中元素的個(gè)數(shù):(rear- front + maxSize) % MaxSize
- 入隊(duì):rear = (rear + 1) % maxSize
- 出隊(duì):front = (front + 1) % maxSize
(一) 順序隊(duì)列的類型定義
#ifndef _SEQQUEUE_H_#define _SEQQUEUE_H_#include "Queue.h"?template <class T>class seqQueue:public Queue<T> {private://指向存放元素的數(shù)組 T &data;//隊(duì)列的大小 int maxSize;//定義隊(duì)頭和隊(duì)尾指針 int front, rear;//擴(kuò)大隊(duì)列空間 void resize();public: seqQueue(int initSize = 100);~seqQueue() {delete []data;}//清空隊(duì)列 void clear() {front = rear = -1;}//判空bool empty() const {return front == rear;} //判滿bool full() const {return (rear + 1) % maxSize == front;}//隊(duì)列長(zhǎng)度int size() const {(rear- front + maxSize) % maxSize;}//入隊(duì)void enQueue(const T &x);//出隊(duì) T deQueue();//取隊(duì)首元素T getHead() const; }; ?#endif(二) 初始化一個(gè)空隊(duì)列
template <class T>seqQueue<T>::seqQueue(int initSize) {if (initSize <= 0) throw badSize();data = new T[initSize];maxSize = initSize;front = rear = -1; }(三) 入隊(duì)
template <class T>void seqQueue<T>::enQueue(const T &x) {//隊(duì)滿則擴(kuò)容 if ((rear + 1) % maxSize == front) resize();//移動(dòng)隊(duì)尾指針 rear = (rear + 1) % maxSize;//x 入隊(duì) data[rear] = x;}(四) 出隊(duì)
template <class T>T seqQueue<T>::deQueue() {//隊(duì)列為空則拋出異常 if (empty()) throw outOfRange();//移動(dòng)隊(duì)尾指針 front = (front + 1) % maxSize;//x入隊(duì) return data[front];}(五) 取隊(duì)首元素
template <class T>T seqQueue<T>::getHead() const {if (empty()) throw outOfRange();//返回隊(duì)首元素,不移動(dòng)隊(duì)首指針 return data[(front + 1) % maxSize];}(六) 擴(kuò)大隊(duì)列空間
template <class T>void seqQueue<T>::resize() {T *p = data;data = new T[2 *maxSize];for(int i = 1; i < size(); ++i)//復(fù)制元素 data[i] = p[(front + i) % maxSize];//設(shè)置隊(duì)首和隊(duì)尾指針 front = 0; rear = size();maxSize *= 2;delete p;}鏈隊(duì)列
用鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)表示隊(duì)列我們叫做鏈隊(duì)列,用無頭結(jié)點(diǎn)的單鏈表表示隊(duì)列,表頭為隊(duì)頭,表尾為隊(duì)尾,需要兩個(gè)指針分別指向隊(duì)頭元素和隊(duì)尾元素,這種存儲(chǔ)結(jié)構(gòu)的好處之一就是不會(huì)出現(xiàn)隊(duì)列滿的情況
(一) 順序隊(duì)列的類型定義
#ifndef _LINKQUEUE_H_#define _LINKQUEUE_H_#include <iostream>#include "Queue.h"?template <class T>class linkQueue:public Queue<T> {private:struct node {T data;node *next;node (const T &x, node *N = NULL) {data = x;next = N;}node ():next(NULL){}~node () {} };node *front, *rear;public: linkQueue(){front = rear = NULL;};~linkQueue() {clear();}//清空隊(duì)列 void clear();//判空bool empty() const {return front == NULL;} //隊(duì)列長(zhǎng)度int size() const;//入隊(duì)void enQueue(const T &x);//出隊(duì) T deQueue();//取隊(duì)首元素T getHead() const; };?#endif(二) 清空隊(duì)列
template <class T>void linkQueue<T>::clear() {node *p;//釋放隊(duì)列中所有節(jié)點(diǎn) while(front != NULL) {p = front;front = front -> next;delete p;}//修改尾指針 rear = NULL;}(三) 求隊(duì)列長(zhǎng)度
template <class T>int linkQueue<T>::size() const {node *p = front;int count = 0;while(p) {count++;p = p -> next;} return count;}(四) 入隊(duì)
template <class T>void linkQueue<T>::enQueue(const T &x) {if(rear == NULL) front = rear = new node(x);else {rear -> next = new node(x);rear = rear -> next;}}(五) 出隊(duì)
template <class T>T linkQueue<T>::deQueue() {//隊(duì)列為空則拋出異常 if (empty()) throw outOfRange();node *p = front;//保存隊(duì)首元素 T value = front -> data;front = front -> next;if (front == NULL)rear = NULL;delete p;return value;}(六) 取隊(duì)首元素
template <class T>T linkQueue<T>::getHead() const {if (empty()) throw outOfRange();return front -> data; }結(jié)尾:
如果文章中有什么不足,或者錯(cuò)誤的地方,歡迎大家留言分享想法,感謝朋友們的支持!
如果能幫到你的話,那就來關(guān)注我吧!如果您更喜歡微信文章的閱讀方式,可以關(guān)注我的公眾號(hào)
在這里的我們素不相識(shí),卻都在為了自己的夢(mèng)而努力 ?一個(gè)堅(jiān)持推送原創(chuàng)開發(fā)技術(shù)文章的公眾號(hào):理想二旬不止
總結(jié)
以上是生活随笔為你收集整理的环形队列出队的元素怎么输出出来_队列的知识讲解与基本实现(数据结构)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 连上WiFi后,笔记本离路由器比较近时,
- 下一篇: jdbcTemplate测试报错:没有合