Java?循環(huán)隊(duì)列/環(huán)形隊(duì)列的實(shí)現(xiàn)流程
之前,我們使用鏈表實(shí)現(xiàn)了基礎(chǔ)隊(duì)列,鏈接放在這里可以去康康喲
Java棧和基礎(chǔ)隊(duì)列的實(shí)現(xiàn)詳解
之所以沒有選擇數(shù)組來實(shí)現(xiàn),是因?yàn)槊坑幸粋€(gè)元素出隊(duì),數(shù)組中所有剩下的元素都需要向前移動一次,因此沒有鏈表高效。
此時(shí),我們就引出了循環(huán)隊(duì)列的概念。
循環(huán)隊(duì)列,又稱環(huán)形隊(duì)列,邏輯上是一個(gè)環(huán),物理上依然是線性表。
head-指向隊(duì)列的第一個(gè)元素
tail-指向隊(duì)列最后一個(gè)元素的下一個(gè)位置
當(dāng)tail走到數(shù)組末尾時(shí),下一步再次返回?cái)?shù)組頭部(從0開始)
出隊(duì)之后的元素就訪問不到了,此時(shí)邏輯上已經(jīng)將它刪除了,tail向后走到該位置時(shí)覆蓋它即可。此時(shí)就解決了數(shù)組隊(duì)列需要一直搬運(yùn)元素的問題。
了解循環(huán)隊(duì)列的概念之后,我們就能明白它的幾個(gè)基礎(chǔ)知識:
當(dāng)head == tail 時(shí),表示隊(duì)列為空
根據(jù)上面 head 和 tail 的定義,隊(duì)列已滿時(shí),tail 指向最后一個(gè)元素的下一個(gè)位置,也就是head ,此時(shí)我們就無法區(qū)分環(huán)形隊(duì)列到底是已滿還是為空。所以我們在環(huán)形隊(duì)列的數(shù)組中浪費(fèi)一個(gè)空間,在區(qū)分?jǐn)?shù)組是否已滿,如下圖,就是一個(gè)已滿的隊(duì)列
那么如何移動 tail 指針使他返回?cái)?shù)組頭部呢?我們運(yùn)用取模操作:
tail = ( tail + 1 ) % 數(shù)組.length;
根據(jù)上式我們就能判斷隊(duì)列是否已滿的方法:
( tail + 1 ) % 數(shù)組.length == head;
此時(shí) head 和 tail 引用向后移動時(shí),不能簡單的 +1,要 ++ 之后對數(shù)組長度取模,這樣就可以返回?cái)?shù)組頭部繼續(xù)向后移動:
head = ( head +1 ) % 數(shù)組.length;
tail = ( tail +1 ) % 數(shù)組.length;
那么如何獲取當(dāng)前隊(duì)列最后一個(gè)元素的索引呢?
圖①中最后一個(gè)元素的索引就是 tail -1
圖②的tail恰好在數(shù)組第一個(gè)位置,這時(shí)最后一個(gè)元素下標(biāo)就是 數(shù)組.length -1
綜上:數(shù)組最后一個(gè)元素的索引lastIndex
lastIndex = tail == 0 ? 數(shù)組.length -1 : tail -1;
代碼實(shí)現(xiàn):
public interface Queue<E> { void offer(E val);//入隊(duì) E poll();//出隊(duì),返回出隊(duì)的值 E peek();//返回隊(duì)首元素 boolean isEmpty();//判斷是否為空 } import java.util.NoSuchElementException; //基于整型的循環(huán)隊(duì)列 public class LoopQueue implements Queue<Integer>{ private Integer[] data; private int head;//隊(duì)首元素 private int tail;//隊(duì)尾元素的下一個(gè)位置 private int size;//當(dāng)前元素個(gè)數(shù) public LoopQueue(int n){ //n為希望保存的元素個(gè)數(shù) //在循環(huán)隊(duì)列中要浪費(fèi)一個(gè)元素空間,來判斷是否已滿,所以 +1 data = new Integer[n + 1]; } @Override //添加元素 public void offer(Integer val) { if(isFull()){ throw new ArrayIndexOutOfBoundsException("queue is full, cannot offer new val"); } data[tail] = val; //tail向后移 tail = (tail + 1) % data.length; size++; } @Override //出隊(duì) public Integer poll() { if (isEmpty()){ throw new NoSuchElementException("queues empty!cannot poll"); } Integer val = data[head]; //head向后移動 head = (head + 1) % data.length; size--; return val; } @Override public Integer peek() { if (isEmpty()){ throw new NoSuchElementException("queues empty!cannot poll"); } return data[head]; } @Override //判斷是否為空 public boolean isEmpty() { return tail == head; } public String toString(){ StringBuilder sb = new StringBuilder(); sb.append("front["); //取得最后一個(gè)元素的下標(biāo) int lastIndex = tail == 0 ? data.length-1 : tail-1; for (int i = head; i != tail; ) { sb.append(data[i]); if (i != lastIndex){ sb.append(","); } i = (i+1) % data.length; } sb.append("]tail"); return sb.toString(); } //判斷隊(duì)列是否已滿 public boolean isFull(){ return (tail + 1) % data.length == head; } }
//代碼測試 public class LoopQueueTest { public static void main(String[] args) { Queue<Integer> loopQueue = new LoopQueue(5); for (int i = 0; i < 5; i++) { loopQueue.offer(i+1); } System.out.println(loopQueue); // loopQueue.offer(1); System.out.println(loopQueue.poll()); System.out.println(loopQueue); } }
運(yùn)行結(jié)果:
到此這篇關(guān)于Java 循環(huán)隊(duì)列/環(huán)形隊(duì)列的實(shí)現(xiàn)流程的文章就介紹到這了,更多相關(guān)Java 循環(huán)隊(duì)列內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
初次使用IDEA創(chuàng)建maven項(xiàng)目的教程
這篇文章主要介紹了初次使用IDEA創(chuàng)建maven項(xiàng)目的教程講解,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-01-01Java連接MYSQL數(shù)據(jù)庫的詳細(xì)步驟
這篇文章主要為大家介紹了Java連接MYSQL數(shù)據(jù)庫的詳細(xì)步驟,感興趣的小伙伴們可以參考一下2016-05-05IDEA 中使用 ECJ 編譯出現(xiàn) java.lang.IllegalArgumentException的錯(cuò)誤問題
這篇文章主要介紹了IDEA 中使用 ECJ 編譯出現(xiàn) java.lang.IllegalArgumentException問題 ,本文內(nèi)容簡短給大家介紹的好,需要的朋友可以參考下2020-05-05詳解Spring Boot 2.0.2+Ajax解決跨域請求的問題
這篇文章主要介紹了詳解Spring Boot 2.0.2+Ajax解決跨域請求的問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03完美解決Server?returned?HTTP?response?code:403?for?URL報(bào)錯(cuò)問題
在調(diào)用某個(gè)接口的時(shí)候,突然就遇到了Server?returned?HTTP?response?code:?403?for?URL報(bào)錯(cuò)這個(gè)報(bào)錯(cuò),導(dǎo)致獲取不到接口的數(shù)據(jù),下面小編給大家分享解決Server?returned?HTTP?response?code:403?for?URL報(bào)錯(cuò)問題,感興趣的朋友一起看看吧2023-03-03一篇文章教你如何用Java自定義一個(gè)參數(shù)校驗(yàn)器
這篇文章主要介紹了使用java自定義一個(gè)參數(shù)校驗(yàn)器,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)2021-09-09