1. 程式人生 > 實用技巧 >資料結構與演算法--佇列的陣列實現

資料結構與演算法--佇列的陣列實現

佇列介紹

1.佇列是一個**有序列表**,可以使用**陣列和連結串列**實現

2.**先入先出**的原則;

佇列分類

順序佇列

       順序佇列一般會設定兩個指標(front和rear)進行管理,front指向佇列的**第一個**元素,rear指向**最後一個元素的下一個位置**,**初始值都為0**。

        每次在隊尾插入一個元素是:rear+1;

        每次在隊頭刪除一個元素是:front+1;當front+rear時佇列為空。

   順序佇列的溢位現象:
        “下溢”現象:當佇列為空時,做出隊運算產生的溢位現象。“下溢”是正常現象,常用作**程式控制轉移**的條件。

        “真上溢”現象:當佇列滿時,做入佇列運算產生空間溢位現象。“真上溢”是一種出錯狀態,須要避免

        “假上溢”現象:由於入隊和出隊操作中,頭指標只增加不減少,使被刪除元素的空間永遠無法重新利用。當佇列中實際元素個數小於向量空間的規模時,也可能由於尾指標已超越向量空間的上界而不能入隊。

   順序佇列的缺陷:
         當rear增加到指向分配的連續空間之外時,佇列無法再插入新元素,但這時往往還有大量可用空間未被佔用,這些空間是已經出隊的佇列元素曾經佔用過的儲存單元。也就是陣列使用一次之後不能再使用了,沒有達到複用的效果

缺陷解決思路:

    (1)佇列元素的出列是在隊頭,即下標為0的地方,每次出隊佇列中的所有元素都要向前移動,保證佇列的隊頭,就是下標為0的位置不為空,此時時間複雜度為o(n),(每次出佇列時所有元素都要前移,效能有所降低)

     (2) 可以設定front指標個rear指標越界時,從頭開始迴圈,即迴圈佇列

迴圈佇列

    定義:無論插入或刪除,一旦rear指標+1或front+1時超出了所分配的佇列空間,就讓它指向這片連續空間的起始位置,之中頭尾相接的順序儲存結構成為迴圈佇列。

    front指標指向佇列的**第一個**元素,rear指標只想**最後一個元素的下一個位置**,初始值都為0。當**front==rear**時為空佇列。如圖:

問題來了呀!!!下圖再入列a7時rear==front,此時就不是空佇列,與上面矛盾了啊

所以當佇列滿時,我們修改其條件,保留一個元素空間。也就是說佇列滿時,陣列中還有一個空閒單元,如下圖就是佇列滿啦:

陣列最大容量為QueueSize,佇列滿的條件(rear+1)% QueueSize == front(%的目的就是為了整合front和rear大小的問題)

佇列長度分為兩段,一段是QueueSize-front,另一段是0+rear,加在一起**佇列的長度為(rear-front+QueueSize)%QueueSize。

迴圈佇列程式碼如下:
`

    import java.util.Scanner;

    public class CircleArrayQueueDemo {
    public static void main(String[] args) {
    System.out.println("測試陣列模擬環形佇列···");

    //建立一個環形佇列
    CircleArray queue = new CircleArray(4);//有效資料最大為3
    char key = ' ';//接收使用者輸入
    Scanner scanner = new Scanner(System.in);
    boolean loop = true;
    //輸出一個選單
    while (loop) {
        System.out.println("s(show):顯示佇列");
        System.out.println("e(exit):退出程式");
        System.out.println("a(add):新增資料到佇列");
        System.out.println("g(get):從佇列取出資料");
        System.out.println("h(head):檢視佇列頭的數");
        key = scanner.next().charAt(0);//接收一個字元
        switch (key) {
            case 's':
                queue.showQueue();
                break;
            case 'a':
                System.out.println("輸出一個數");
                int value = scanner.nextInt();
                queue.addQueue(value);
                break;
            case 'g':
                try {
                    int res = queue.getQueue();
                    System.out.printf("取出的資料是%d\n", res);
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                }
                break;
            case 'h':
                try {
                    int res = queue.headQueue();
                    System.out.printf("佇列頭的資料是%d\n", res);
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                }
                break;
            case 'e':
                scanner.close();
                loop = false;
                break;
            default:
                break;
        }
    }
    System.out.println("程式退出···");
}}
class CircleArray {

private int maxSize;

//front優化後:front指向佇列的第一個元素,arr[front]是佇列的第一個值,front初始值為0
private int front;

//rear優化後:rear指向佇列的最後一個元素的後一個位置,空出一個位置做為約定,rear初始值為0
private int rear;
private int[] arr;

public CircleArray(int arrMaxSize) {
    maxSize = arrMaxSize;
    arr = new int[maxSize];
    //預設為0
    //front = 0;
    //rear = 0;
}

public boolean isFull() {
    return (rear + 1) % maxSize == front;
}

public boolean isEmpty() {
    return rear == front;
}

public void addQueue(int n) {
    if (isFull()) {
        System.out.println("佇列滿,無法新增資料!");
        return;
    }
    //直接將資料加入
    arr[rear] = n;
    //將rear後移,必須考慮取模
    rear = (rear + 1) % maxSize;
}

public int getQueue() {
    if (isEmpty()) {
        throw new RuntimeException("佇列空,無法取出資料!");
    }
    //分析出front是指向佇列的第一個元素
    //1.先把front對應的值保留到一個臨時變數中
    //2.將front後移,考慮取模
    //3.將臨時儲存的變數返回
    int value = arr[front];
    front = (front + 1) % maxSize;
    return value;
}

public void showQueue() {
    if (isEmpty()) {
        System.out.println("佇列空,沒喲資料!");
        return;
    }
    for (int i = front; i < front + size(); i++) {
        System.out.printf("add[%d]=%d\n", i % maxSize, arr[i % maxSize]);
    }
}

//求出當前佇列有效的個數
public int size() {
    return (rear + maxSize - front) % maxSize;
}

public int headQueue() {
    if (isEmpty()) {
        throw new RuntimeException("佇列空,沒有資料!");
    }
    return arr[front];
}}

`