Java 單向隊列及環形隊列的實現原理

隊列的特點

1.可以使用數組和鏈表兩種方式來實現。

2.遵循先入先出(FIFO)的規則,即先進入的數據先出。

3.屬於有序列表。

圖解實現過程:

​1.定義一個固定長度的數組,長度為maxSize。

​2.設置兩個指針first = -1(指向隊列第一個數據的前一位,這樣保證在添加第一個數據以後頭指針為0,和數組的下標一樣,且用於操作出隊)和last = -1(指向隊尾,用於操作入隊)。

​3.即first會因為出隊操作而增加,last會因為入隊操作而增加

代碼實現:

package 隊列;

public class ArrayQueueTest {
    public static void main(String[] args) {
        ArrayQueue arrayQueue = new ArrayQueue(3);
        arrayQueue.addQueue("瓊");
        arrayQueue.addQueue("贇");
        arrayQueue.addQueue("瓏");
        arrayQueue.showAllQueueData();
        System.out.println(arrayQueue.getQueue());   
    }
}
class ArrayQueue{
    private int maxSize;//定義隊列的最大長度
    private int first ;//指向隊列頭的前一個位置!!前一個位置!!出隊方向
    private int last ;//指向隊列尾部!!即最後一個數據!!!入隊方向
    private String[] arr; //先建一個空的數組,具體長度未知,需要maxSize來確定。
	
    //構造器初始化隊列信息
    public ArrayQueue(int maxSize){
        this.maxSize = maxSize;
        this.first = -1;
        this.last = -1;
        arr = new String[maxSize];
    }
	
    //判斷是否為空
    public boolean isEmpty(){
        if (first == last) {
            System.out.println("隊列為空~~");
            return true;
        }else {
            System.out.println("隊列不為空~~");
            return false;
        }
    }
    
    //判斷隊列是否滿
    public boolean isFull(){
        if (last == maxSize-1) {
            System.out.println("隊列已滿~~");
            return true;
        }else {
            System.out.println("隊列未滿~~");
            return false;
        }
    }
	
    //入隊
    public void addQueue(String data){
        if (last == maxSize-1){
            System.out.println("隊列已滿,不能再添加!!");
            return;
        }else {
            last++; //添加數據隻和末尾下標有關
            arr[last] = data;
            return;
        }
    }
	
    //出隊
    public String getQueue(){
        if (isEmpty()) {
            //因為getQueue方法是int型,需要返回數據,如果無數據,也需要返回
            //如果返回-1或者其他數據,會讓人誤解獲取到的數就是-1或者其他
            //所以用拋出異常來處理
            throw new RuntimeException("隊列為空,無數據~~");
        }
        else {
            first++;
            return arr[first];
        }
    }
	
    //遍歷隊列所有信息
    public void showAllQueueData(){
        if (first == last){
            return;
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.println("arr["+i+"]"+"="+arr[i]);
        }
    }
	
    //獲取隊列頭數據
    public String headQueueData(){
        if (isEmpty()){
            throw new RuntimeException("無數據~~~");
        }
        return arr[++first];
    }
}

隊列缺點:

由於出隊操作,使得first指針上移變大,導致數組前面空出來的位置就不能再繼續添加數據,即不能再被重復使用,這樣一個隊列隻能使用一次,內存效率太低,所以需要使用環形隊列來優化解決。

優化解決——環形隊列實現思路

1.first指針初始默認設置為0,指向隊列頭部,則arr[first] 就是第一個數據。

2.last指針初始默認也為0,但是會隨著增加數據而後移。

3.隊列滿的條件:

(last + 1) % maxSize == first

​last+1是為瞭讓指針後移,而且如果不設置為 last+1 那麼一開始的時候last為0 , last % maxSize == 0,且first也為0,還沒加數據就滿瞭。

4.隊列為空的條件:

first == last

5.由於判斷是否滿的時候: last+1 ,導致實際上可以裝的數據比數組長度少 1

環形隊列各步驟及各方法實現講解

1.隊列初始化 :

class CircleArryQueue{
    private int maxSize ; //數組長度,即隊列最大容量
    private int first; 	  //頭指針,控制出隊操作
    private int last;	  //尾指針,控制入隊操作
    private int[] arr;	  //數組類型,可以換其他的。

    //構造器初始化信息
    public CircleArryQueue(int maxSize){
        this.maxSize = maxSize;
        this.arr = new int[maxSize];
        this.first = 0;		//這兩個可以不加,不叫也是默認為0
        this.last = 0;
    }
}

2.判斷隊列是否為空:

 public boolean isEmpty(){
        //頭指針和尾指針一樣 則說明為空
        return last == first;
    }

3.判斷隊列是否滿:

/*
*這裡的 last+1 主要是為瞭讓指針後移,特別是在隊列尾部添加數據的時候,本來用last也可以判斷,但
*是一開始還沒加數據的時候,如果直接用last % maxSize == first,結果是true,所以為瞭解決指針後*移和判斷是否滿,用來last+1。其次,因為last+1可能會導致數組指針越界,所以用取模來控制它的范  * 圍,同時保證他會在一個固定的范圍循環變換,也利於環形隊列的實現。
*/
public boolean isFull(){
    return (last + 1) % maxSize == first;
}

4.添加數據到隊列尾部:入隊

public void pushData(int data){
    //先判斷是否滿瞭
    if(isFull()){
        System.out.println("隊列已經滿啦~~");
        return;
    }
    arr[last] = data;
    //last+1是為瞭後移,取模是為瞭避免指針越界,同時可以讓指針循環
    last = (last + 1) % maxSize;
}

5.取出隊首數據:出隊

public int popData(){
        if (isEmpty()) {
            //拋異常就可以不用返回數據瞭
            new RuntimeException("隊列為空,沒有獲取到數據~~");
        }
    
 		//要先把first對應的數組數據保存——>first後移——>返回數據
        int value = arr[first];
		//first+1的操作和last+1是一樣的,取模也是 
        first = (first+1) % maxSize;
        System.out.println(value);
        return value;
    	//如果不保存first指針 那麼返回的數據就不對瞭
		//如果直接返回數據,那first指針還沒後移 也不對,所以需要使用第三方變量
    }

6.展示隊列中所有數據:

public void showAllData(){
        if (isEmpty()) {
            System.out.println("隊列為空,沒有數據~~");
            return;
        }
		//此處i不為0,是因為有可能之前有過popData()操作,使得firs不為0,所以最好使用
    	//first給i動態賦值,
        for (int i = first; i < first+size() ; i++) {
            System.out.println("arr["+i%maxSize+"]"+arr[i%maxSize]);
        }

7.獲取隊列中數據的總個數:

public int dataNum(){
	//韓順平老師的教程上是這樣寫,但是我理解不瞭..........。
	return (last+maxSize-first) % maxSize;   
}

8.查看隊首數據但不彈出:

public void seeFirstData(){
    return arr[first];
}

全部代碼整合:

package 練習;

import java.util.Scanner;

public class CircleArryQueue {
    public static void main(String[] args){
        CircleQueue circleQueue = new CircleQueue(4);
        System.out.println("--------測試環形隊列--------");
        char key = ' ';
        Scanner scanner = new Scanner(System.in);

        boolean flag = true;
        while (flag){
            System.out.println("s(showAllData):查看隊列數據");
            System.out.println("p(pushData):隊尾添加數據");
            System.out.println("g(popData):彈出隊頭數據");
            System.out.println("h(seefirstData):獲取隊頭數據");
            System.out.println("e(exit):退出程序");
            key = scanner.next().charAt(0);

            switch (key){
                case 's':
                    circleQueue.showAllData();
                    break;
                case 'p':
                    System.out.println("輸入一個數據:");
                    int obj = scanner.nextInt();
                    circleQueue.pushData(obj);
                    break;
                case 'g':
                    circleQueue.popData();
                    break;
                case 'h':
                    circleQueue.seeFirstData();
                    break;
                case 'e':
                    scanner.close();
                    flag = false;
                    break;
                default:
                    break;
            }

        }

        System.out.println("程序結束~~~");

    }

}

class CircleQueue {
    private int maxSize ; //數組長度,即隊列最大容量
    private int first; 	  //頭指針,控制出隊操作
    private int last;	  //尾指針,控制入隊操作
    private int[] arr;	  //數組類型,可以換其他的。

    //構造器初始化信息
    public CircleQueue(int maxSize){
        this.maxSize = maxSize;
        this.arr = new int[maxSize];
        this.first = 0;		//這兩個可以不加,不叫也是默認為0
        this.last = 0;
    }

    public boolean isEmpty(){
        //頭指針和尾指針一樣 則說明為空
        return last == first;
    }

/*
*這裡的 last+1 主要是為瞭讓指針後移,特別是在隊列尾部添加數據的時候,本來用last也可以判斷但
*是一開始還沒加數據的時候,如果直接用last % maxSize == first,結果是true,所以為瞭解決指針
*後移和判斷是否滿,用來last+1。其次,因為last+1可能會導致數組指針越界,所以用取模來控制它
*的范圍,同時保證他會在一個固定的范圍循環變換,也利於環形隊列的實現。
*/
    public boolean isFull(){
        return (last + 1) % maxSize == first;
    }

    public void pushData(int data){
        //先判斷是否滿瞭
        if(isFull()){
            System.out.println("隊列已經滿啦~~");
            return;
        }
        arr[last] = data;
        //last+1是為瞭後移,取模是為瞭避免指針越界,同時可以讓指針循環
        last = (last + 1) % maxSize;
    }

    public int popData(){
        if (isEmpty()) {
            //拋異常就可以不用返回數據瞭
            throw new RuntimeException("隊列為空,沒有獲取到數據~~");
        }

        //要先把first對應的數組數據保存——>first後移——>返回數據
        int value = arr[first];
        //first+1的操作和last+1是一樣的,取模也是
        first = (first+1) % maxSize;
        System.out.println(value);
        return value;
        //如果不保存first指針 那麼返回的數據就不對瞭
        //如果直接返回數據,那first指針還沒後移 也不對,所以需要使用第三方變量
    }
    
	//查看所有數據
    public void showAllData(){
        if (isEmpty()) {
            System.out.println("隊列為空,沒有數據~~");
        }
        //此處i不為0,是因為有可能之前有過popData()操作,使得firs不為0,所以最好使用
        //first給i動態賦值,
        for (int i = first; i < first+dataNum() ; i++) {
            System.out.println("arr["+i%maxSize+"]"+arr[i%maxSize]);
        }
    }
	//查看有效數據個數
    public int dataNum(){
        //韓順平老師的教程上是這樣寫,但是我理解不瞭..........。
        return (last+maxSize-first) % maxSize;
    }
	//查看隊列第一個數據
    public int seeFirstData(){    
        System.out.println(arr[first]);
        return arr[first];
        
    }
}

最後:

部分內容參考自B站韓順平老師java數據結構課程

到此這篇關於Java 單向隊列及環形隊列的實現原理的文章就介紹到這瞭,更多相關Java 單向隊列及環形隊列內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: