Java 單向隊列及環形隊列

  • 隊列的特色

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

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

    3.屬於有序列表。數據結構

  • 圖解實現過程:

1.定義一個固定長度的數組,長度爲maxSize。測試

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

3.即first會由於出隊操做而增長,last會由於入隊操做而增長this


  • 代碼實現:

    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,可是會隨着增長數據然後移。code

    3.隊列滿的條件:blog

    (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數據結構課程,因爲筆者水平有限,整理的博文中不免有不不足和理解不對的地方,歡迎留言批評指正。碼字不易,調試費神。歡迎轉載轉發,但請註明出處。若有幫助,歡迎打賞一杯咖啡調試bug。

相關文章
相關標籤/搜索