java數(shù)據(jù)結(jié)構(gòu)循環(huán)隊(duì)列的空滿(mǎn)判斷及長(zhǎng)度計(jì)算
在上一章中,使用了數(shù)組模擬了隊(duì)列。但是留下的問(wèn)題是,把數(shù)據(jù)取完后,再往里加數(shù)據(jù)就不行了。
一、假溢出
這是因?yàn)閿?shù)組的末尾已經(jīng)被占用了,入隊(duì)會(huì)繼續(xù)在數(shù)組后面增加,于是產(chǎn)生數(shù)組越界。但是實(shí)際上,數(shù)組里是有空閑位置的,這種也可以叫“假溢出”。

為了解決“假溢出”的問(wèn)題,于是乎有了循環(huán)隊(duì)列。
既然數(shù)組后面滿(mǎn)了,頭部有空,那繼續(xù)加進(jìn)來(lái)的元素從頭開(kāi)始放即可。
接著上圖,這時(shí)候有a6入隊(duì),于是rear的下標(biāo)指向a6的下一個(gè)元素位置,看起來(lái)沒(méi)什么問(wèn)題。

但是繼續(xù)有新的元素a7入隊(duì)的時(shí)候,因?yàn)閒ront一直沒(méi)變,這時(shí)候rear指針跟front就重合了,也就是說(shuō)此時(shí)front=rear。

可是在上一章的代碼里,我們是用front=rear來(lái)判斷是否為空數(shù)組的。
// 判斷隊(duì)列是否為空
public boolean isEmpty() {
return rear == front;
}現(xiàn)在是相等了,條件滿(mǎn)足,但是數(shù)組是滿(mǎn)的。
二、循環(huán)隊(duì)列判斷是空是滿(mǎn)
這種情況看起來(lái)確實(shí)比較辣手,那如果不讓這種情況出現(xiàn)不就可以了么?
假設(shè),我們讓數(shù)組始終保留一個(gè)元素空間,也就是讓rear指向隊(duì)列中最后一個(gè)元素的后一個(gè)位置。比如,當(dāng)a6放入之后,此時(shí)就當(dāng)做隊(duì)列已經(jīng)滿(mǎn)了,這樣的話(huà)就不會(huì)出現(xiàn)上述的情況了。

為了實(shí)現(xiàn)這種思路,front也需要做調(diào)整。在上一章中,front初始位置是指在了隊(duì)頭元素的前一個(gè),現(xiàn)在我們讓它就指在第一個(gè)元素。
隊(duì)列的最大尺寸還是maxSize,那么,現(xiàn)在判斷隊(duì)列滿(mǎn)的條件就可以是這樣:
(rear+1)%maxSize = front
驗(yàn)證一下,下面的2種隊(duì)列滿(mǎn)情況:

左圖:隊(duì)列中,maxSize=5,front=0,rear=4,判斷(4+1)% 5=0=front,隊(duì)列已滿(mǎn)
右圖:隊(duì)列中,maxSize=5,front=2,rear=1,判斷(1+1)% 5=2=front,隊(duì)列已滿(mǎn)
繼續(xù)驗(yàn)證一下,隊(duì)列沒(méi)滿(mǎn)的情況:

隊(duì)列中,maxSize=5,front=2,rear=0,判斷(0+1)% 5=1≠front,隊(duì)列未滿(mǎn)
三、循環(huán)隊(duì)列的長(zhǎng)度計(jì)算
隊(duì)列的長(zhǎng)度,也就是說(shuō)隊(duì)列中實(shí)際存了多少個(gè)元素。
此時(shí)需要考慮rear與front之間的三種情況:
- rear=front
- rear>front
- rear<front
第一種自然都清楚,隊(duì)列為空。
第二種,rear>front,此時(shí)隊(duì)列的長(zhǎng)度為:rear-front

第三種,rear<front,比較復(fù)雜些。隊(duì)列長(zhǎng)度分為2段:一段是maxSize-front,另一段則是:0+rear(結(jié)合右圖理解)。故此時(shí)隊(duì)列總長(zhǎng)度為兩段相加:rear-front+maxSize

所以隊(duì)列長(zhǎng)度的通用計(jì)算公式為:
(rear-front+maxSize)% maxSize
四、代碼實(shí)現(xiàn)
既然現(xiàn)在隊(duì)列是滿(mǎn)是空的判斷條件有了,隊(duì)列長(zhǎng)度也能計(jì)算出來(lái)了,那么代碼就好改造了(基于上一章),變成循環(huán)隊(duì)列。
package circle;
import java.util.Scanner;
public class CircleArrayQueue {
public static void main(String[] args) {
System.out.println("-----測(cè)試循環(huán)隊(duì)列-----");
// 創(chuàng)建一個(gè)隊(duì)列
CircleArray circleArray = new CircleArray(4);
char key = ' '; //接受用戶(hù)輸入
Scanner scanner = new Scanner(System.in);
boolean loop = true;
// 輸出一個(gè)菜單
while (loop) {
System.out.println("s(show): 顯示隊(duì)列");
System.out.println("e(exit): 退出程序");
System.out.println("a(add): 添加數(shù)據(jù)到隊(duì)列");
System.out.println("g(get): 從隊(duì)列取出數(shù)據(jù)");
System.out.println("h(head): 顯示隊(duì)首的數(shù)據(jù)");
key = scanner.next().charAt(0); // 接收一個(gè)字符
switch (key) {
case 's':
circleArray.showQueue();
break;
case 'a':
System.out.println("請(qǐng)要添加的數(shù)");
int value = scanner.nextInt();
circleArray.addQueue(value);
break;
case 'g':
try {
int res = circleArray.getQueue();
System.out.printf("取出的數(shù)據(jù)是:%d", res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int headValue = circleArray.showHeadQueue();
System.out.printf("隊(duì)首數(shù)據(jù)是:%d", headValue);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'e':
scanner.close();
loop = false;
break;
}
}
System.out.println("退出程序");
}
}
class CircleArray {
//表示數(shù)組最大容量
private int maxSize;
// 隊(duì)列頭,由之前調(diào)整為指向隊(duì)列第一個(gè)元素
private int front;
// 隊(duì)列尾,由之前調(diào)整為指向隊(duì)列最后一個(gè)元素的后一個(gè)位置,為了空出一個(gè)元素位置
private int rear;
// 用于存放數(shù)據(jù)的數(shù)組
private int[] arr;
// 構(gòu)造器
public CircleArray(int arrMaxSize) {
maxSize = arrMaxSize;
arr = new int[maxSize];
front = 0;
rear = 0;
}
// 判斷隊(duì)列是否已經(jīng)存滿(mǎn)
public boolean isFull() {
return (rear + 1) % maxSize == front;
}
// 判斷隊(duì)列是否為空
public boolean isEmpty() {
return rear == front;
}
// 添加數(shù)據(jù)到隊(duì)列
public void addQueue(int num) {
// 判斷隊(duì)列是否滿(mǎn)了
if (isFull()) {
System.out.println("隊(duì)列已滿(mǎn),不可加入數(shù)據(jù)");
return;
}
arr[rear] = num;
// 將rear后移,要考慮取模
rear = (rear + 1) % maxSize;
}
// 拿出隊(duì)列數(shù)據(jù)
public int getQueue() {
// 判斷隊(duì)列是否空
if (isEmpty()) {
// 拋出異常
throw new RuntimeException("隊(duì)列為空,不可取數(shù)據(jù)");
}
int tempValue = arr[front];
front = (front + 1) % maxSize; //也要考慮取模,防止front不停的增加,導(dǎo)致越界
return tempValue;
}
// 顯示隊(duì)列所有數(shù)據(jù)
public void showQueue() {
// 遍歷
if (isEmpty()) {
System.out.println("隊(duì)列為空");
return;
}
// 從front開(kāi)始遍歷,遍歷多少個(gè)實(shí)際存的元素即可
for (int i = front; i < front + CircleQueueSize(); i++) {
System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
}
}
// 求出當(dāng)前隊(duì)列有效數(shù)據(jù)的個(gè)數(shù)
public int CircleQueueSize() {
return (rear - front + maxSize) % maxSize;
}
// 顯示隊(duì)里的隊(duì)首數(shù)據(jù)
public int showHeadQueue() {
if (isEmpty()) {
// 拋出異常
throw new RuntimeException("隊(duì)列為空,不可取數(shù)據(jù)");
}
return arr[front];
}
}重點(diǎn)的改動(dòng)在于取模。
以上就是java數(shù)據(jù)結(jié)構(gòu)循環(huán)隊(duì)列的空滿(mǎn)判斷及長(zhǎng)度計(jì)算的詳細(xì)內(nèi)容,更多關(guān)于java循環(huán)隊(duì)列空滿(mǎn)判斷長(zhǎng)度計(jì)算的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Java?C++?算法題解leetcode145商品折扣后最終價(jià)格單調(diào)棧
- Java算法真題詳解運(yùn)用單調(diào)棧
- Java 數(shù)據(jù)結(jié)構(gòu)算法Collection接口迭代器示例詳解
- java數(shù)據(jù)結(jié)構(gòu)與算法數(shù)組模擬隊(duì)列示例詳解
- java數(shù)據(jù)結(jié)構(gòu)算法稀疏數(shù)組示例詳解
- java數(shù)據(jù)結(jié)構(gòu)圖論霍夫曼樹(shù)及其編碼示例詳解
- 特殊數(shù)據(jù)結(jié)構(gòu)之使用Java實(shí)現(xiàn)單調(diào)棧示例
相關(guān)文章
將應(yīng)用程序進(jìn)行Spring6遷移的最佳使用方式
這篇文章主要介紹了將應(yīng)用程序進(jìn)行Spring6遷移的最佳方式,以及如何充分利用此升級(jí),需要的朋友可以參考下,如有錯(cuò)誤的地方還請(qǐng)指正2023-03-03
Resttemplate中設(shè)置超時(shí)時(shí)長(zhǎng)方式
這篇文章主要介紹了Resttemplate中設(shè)置超時(shí)時(shí)長(zhǎng)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
詳解Java使用Jsch與sftp服務(wù)器實(shí)現(xiàn)ssh免密登錄
這篇文章主要介紹了詳解Java使用Jsch與sftp服務(wù)器實(shí)現(xiàn)ssh免密登錄,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
通過(guò)Java壓縮JavaScript代碼實(shí)例分享
這篇文章主要介紹了通過(guò)Java壓縮JavaScript代碼實(shí)例分享,具有一定參考價(jià)值,需要的朋友可以了解下。2017-12-12
Dubbo擴(kuò)展點(diǎn)SPI實(shí)踐示例解析
這篇文章主要為大家介紹了Dubbo擴(kuò)展點(diǎn)SPI實(shí)踐示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
List集合按某個(gè)屬性或者字段進(jìn)行分組的操作
這篇文章主要介紹了List集合按某個(gè)屬性或者字段進(jìn)行分組的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
Java8中Optional的一些常見(jiàn)錯(cuò)誤用法總結(jié)
我們知道 Java 8 增加了一些很有用的 API, 其中一個(gè)就是 Optional,下面這篇文章主要給大家介紹了關(guān)于Java8中Optional的一些常見(jiàn)錯(cuò)誤用法的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2018-07-07
如何使用 Shell 腳本查看多個(gè)服務(wù)器的端口是否打開(kāi)的方法
這篇文章主要介紹了如何使用 Shell 腳本來(lái)查看多個(gè)服務(wù)器的端口是否打開(kāi)的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06

