1. 程式人生 > >Java 單向佇列及環形佇列

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

相關推薦

Java 單向佇列環形佇列

佇列的特點 1.可以使用陣列和連結串列兩種方式來實現。 2.遵循先入先出(FIFO)的規則,即先進入的資料先出。 3.屬於有序列表。 圖解實現過程: ​ 1.定義一個固定長度的陣列,長度為maxSize。 ​ 2.設定兩個指標first = -1(指向佇列第一個資料的前一位,這樣保證在新增第一 個數據

佇列迴圈佇列Java實現)

package ch03; /* * 佇列類 */ public class MyQueue { // 底層實現是一個數組 private long[] arr; // 有效資料大小 private int elements; // 隊頭 priva

棧、佇列優先順序佇列

抽象資料型別(ADT) 陣列、連結串列、樹等等都適用於資料庫應用中作資料記錄,常用來記錄對應於現實世界的資料;而棧、佇列及優先順序佇列更多地是作為程式設計師的工具來使用(用最合適的工具幹活),以簡化某些程式操作。 棧、佇列及優先順序佇列都可以使用陣列連結串列來實現,優先順序佇列通常使用堆實現。 在棧、佇

順序佇列佇列

一、實驗目的1.掌握佇列的連結儲存結構—鏈佇列以及順序儲存結構—順序佇列2.驗證鏈佇列的儲存結構和基本的實現3.驗證佇列的操作特性。二、實驗內容1.建立一個空佇列2.對已建立的佇列進行插入、刪除、取隊頭元素等操作三、設計與編碼1.理論知識定義鏈佇列和順序佇列的資料型別如入隊出

python3佇列迴圈佇列基本實現

class Queue(object):# 定義佇列類 為什麼加入object def __init__(self,size): self.size = size #定義佇列長度

順序佇列佇列的基本操作實現

一、實驗目的 1、熟練佇列的結構特點,掌握佇列的順序儲存和鏈式儲存結構和實現。 2、 學會使用佇列解決實際問題。 二、實驗內容 自己確定結點的具體資料型別和問題規模: 分別建立一個順序佇列和鏈佇列,實現佇列的入隊和出隊操作。 三、實驗步驟 1、依據實驗內

java併發包訊息佇列在開源軟體中的應用

1.BlockingQueue的常用方法 BlockingQueue也是java.util.concurrent下的主要用來控制執行緒同步的工具。 主要的方法是:put、take一對阻塞存取;add、poll一對非阻塞存取。          插入:        1

java資料結構——環形佇列

ArrayQueue存在一個問題,假設當尾部插入元素滿了,頭部又刪掉了一些元素,這種情況下,就誤認為空間滿了,造成了假溢位,實際上頭部刪除了元素留出了空間。這時候環形佇列就解決了這樣的一個問題,環形

golang 實現一種環形佇列週期任務

一、環形佇列 環形佇列不同語言有很多種不同的實現,不過大部分都比較複雜。 在使用golang實踐生產者消費者模型時,發現了一種變相的環形佇列,程式碼比“常規的”環形佇列簡單的多,解決2個問題: 1、生產者消費者間資料傳遞; 2、記憶體空間預申請,避免頻繁的動態記

Java實現環形佇列

這裡我定義的環形佇列為:列表中最後一個元素是指向列表中的第一個元素,而且裡面提供一個next方法,可以不斷獲取下一個元素,在環形佇列中也就是不斷的轉圈,實現方式如下: 佇列中提供的方法: public boolean add(E e):加入佇列

java環形佇列的實現

/**  * Array-based implementation of the queue.  * @author zhang  yin ye    *@email:[email protected]  */ public class ArrayQueue&l

Java實現環形佇列(入隊、出隊)

public class Class_queue {     private int q_head;     private int q_tail;     private int[] queue;     private int len;     private int

Java併發包原始碼學習系列:CLH同步佇列同步資源獲取與釋放

[toc] ## 本篇學習目標 - 回顧CLH同步佇列的結構。 - 學習獨佔式資源獲取和釋放的流程。 ## CLH佇列的結構 我在[Java併發包原始碼學習系列:AbstractQueuedSynchronizer#同步佇列與Node節點](https://www.cnblogs.com/summer

資料結構JAVA版之棧和佇列

一、涉及的內容大綱 二、簡單介紹棧、佇列和其他資料結構的不同 1 對於其他的資料結構而言,都適用與資料庫應用中作資料記錄。但是因為棧和佇列的生命週期比那些資料庫型別的資料結構要短,所以他們只是在程式的操作期間才會建立和執行,在完成任務之後就會被銷燬。所以棧和佇列更多的是用於構思演算法的

堆的應用優先佇列

標頭檔案: #include<queue> 宣告: priority_queue <int> i; priority_queue <double> d; 預設為大根堆,即從大到小排列。  除非: priority_queue &

[LeetCode] Design Circular Queue 設計環形佇列

  Design your implementation of the circular queue. The circular queue is a linear data structure in which the operations are performed based on FIFO

Java用連結串列實現佇列

佇列--先入先出 棧---後入先出 連結串列實現佇列和棧。首先我們需要構建一個連結串列。連結串列有哪幾要素?   1、連結串列本身的value 2、連結串列的next指標,next指標指的還是同樣型別的值。 下邊看程式碼 public class Element&l

Java---之實現資料結構----佇列

package 資料結構;//java之實現佇列 class quene{ private class Data{ private Object obj; private Data next=null; Data(Object obj){

Java併發環境下的佇列(Queue)概述

本文作者:王一飛,叩丁狼高階講師。原創文章,轉載請註明出處。    概念 佇列 佇列是一種特殊的線性表,是一種先進先出(FIFO)的資料結構。它只允許在表的前端(front)進行刪除操作,而在表的後端(rear)進行插入操作。進行插入操作的端稱為隊尾,進行刪除操

uvaoj 133 - The Dole Queue(邏輯,環形佇列數數)

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=69 有n個人向內排成一圈,從一個位置開始逆時針數k個,第k個出隊,從一個位置開始順時針數m