天天看點

一文搞懂資料結構 之 隊列和環形隊列

什麼是隊列?

隊列是一種固定大小的有序清單,它的特點是先進先出。

隊列有四個重要參數,【頭】【尾】【最大長度】【資料區】

在 Java 中的聲明方式:

一文搞懂資料結構 之 隊列和環形隊列
一文搞懂資料結構 之 隊列和環形隊列

當隊列建構完成以後,隊尾和隊首同時指向 位址 1 ,當向隊列插入資料時,隊尾向後移動,直至隊尾等于 maxSize時 ((全文:隊首、隊尾初始值為 0),maxSize = 5) 隊列已滿,我們便無法再向隊列插入資料 

 每當我們取出一個資料,隊首就向後移動一個位址,直至 隊首等于隊尾,所有資料取完,隊列為空。

根據上面的分析,我們可以知道,當隊尾 = 隊首時 隊列為空,當 隊尾 = maxSize 時,隊列已滿。

這是一個傳統的隊列,每當我們取出一個資料,隊列的可用空間就會失去一個,也就是說,這個隊列隻能使用一次。

那麼如何讓隊列空間可以重複利用呢?

循環隊列它來了!循環隊列是通過一定的算法,将一個線性隊列看作一個環,使得這個隊列空間可以重複利用的資料結構。

一文搞懂資料結構 之 隊列和環形隊列

 循環隊列,了解上可以将它了解成一個環,但它實際還是一個線性隊列,隻是再傳統隊列的基礎之上通過算法,使它的空間可以重複利用。

在環形隊列中,我們無法再像傳統隊列那樣,使用隊尾 = maxSize 來判斷隊列是否已滿。

是以,為了能夠判斷隊列是否已經存儲滿,我們需要浪費掉一個空間來判斷是否已滿。而這個空間,始終是隊尾的後一個空間。而這個判斷條件就是,浪費掉的空間 取模 maxSize 是否等于隊首,隊尾的值,始終取 隊尾%maxSize

即 (rear+1)% 8 == front | rear = rear%8

為了了解,這裡做出幾個資料假設:

        假設 隊首(front) 隊尾(rear)maxSize = 8

        下表是填充資料不取出的情況

隊尾(rear) 浪費掉的空間(rear+1)% maxSize 隊首(front) 隊列是否已滿(T/F)
1 F
1 2 F
2 3 F
.... .... .... ....
7 0     ( 8 % 8) T

     填充,并取出兩個資料即 隊首 = 2 (取出0,1兩個位址的資料後,隊首的位置)

隊尾(rear) 浪費掉的空間(rear+1)% maxSize 隊首(front) 隊列是否已滿(T/F)
7 2 F
8 1 ( 8+1 = 9 % 8 ) 2 F
2 (1+1 = 2 % 8) 2 T

     ok,我們總結一下,傳統隊列和循環隊列,空,滿時的條件

滿
傳統隊列 front = rear  rear = maxSize
循環隊列 front = rear  front = (rear+1)%maxSize

        在傳統隊列中,隊首和隊尾的取值最大為maxSize ,而循環隊列中,隊首和隊尾的取值都是在 %maxSize 進行一個循環 即(rear % 8 ,front%8)

最後:書寫不易,多多支援!附上代碼:

傳統隊列

package com.uxteam.data;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/*
*  隊列: 隊列是一種先進先出的線性表,他隻允許從尾部插入資料,頭部删除資料,通常由連結清單或數組實作
*
* */
public class ArrayQueue {
    // 隊列的最大長度
    private int maxSize;
    // 隊列頭部位置
    private int front;
    // 隊列尾部位置
    private int rear;
    // 隊列資料存儲區域
    private int[] data;

    public ArrayQueue(int maxSize){
        init(maxSize);
    }
    // 初始化隊列資料
    private void init(int maxSize){
        this.maxSize = maxSize;
        this.front = 0;
        this.rear = 0;
        this.data = new int[maxSize];
    }

    /**
     * 判斷隊列是否為空
     * @return true / false
     */
    // todo 判斷隊列是否為空 -- 完成
    public boolean isEmpty(){
        return rear - front == 0;
    }

    /***
     * 判斷隊列是否已滿
     * @return true / false
     */
    // todo 判斷隊列是否已滿 -- 完成
    public boolean isFull(){
        return rear == maxSize;
    }
    // todo 向隊列插入元素 -- 完成
    public void insert(int ele){
        // 如果隊列已滿,抛出異常
        if (isFull()){
            throw new RuntimeException("隊列已滿");
        }
        this.data[rear++] = ele;
    }
    // todo 從隊列删除元素 -- 完成
    public int remove(){
        // 如果隊列是空,抛出異常
        if (isEmpty()){
            throw new RuntimeException("隊列為空");
        }
        return this.data[front++];
    }
    // todo 顯示隊列所有元素 -- 完成
    public void list(){
        List<Integer> collect = Arrays.stream(this.data).boxed().collect(Collectors.toList());
        System.out.println(collect.subList(front,rear));
    }
    // todo 顯示隊列頭部元素 -- 完成
    public int first(){
        if (isEmpty()){
            throw new RuntimeException("隊列為空");
        }
        return this.data[front];
    }
}
           

循環隊列

package com.uxteam.data;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class CircleQuque {
    /***
     * 環形隊列最大容量
     */
    private int maxSize;
    /***
     * 隊首位置
     */
    private int front;
    /***
     * 隊尾位置
     */
    private int rear;
    /***
     * 資料區
     */
    private int[] data;

    /***
     * 隊列構造器
     * @param maxSize 隊列最大容量
     */
    public CircleQuque(int maxSize){
        init(maxSize);
    }

    /***
     * 初始化内部參數
     * @param maxSize 隊列最大容量
     */
    private void init(int maxSize){
        this.maxSize = maxSize;
        this.front = 0;
        this.rear = 0;
        this.data = new int[maxSize];
    }
    // todo 判斷隊列是否為空

    /***
     * 判斷隊列是否為空
     * @return true / false
     */
    public boolean isEmpty(){
        return front == rear;
    }
    // todo 判斷隊列是否已滿

    /***
     * 判斷隊列是否已滿
     * @return true / false
     */
    public boolean isFull(){
        return (rear+1)%maxSize == front;
    }
    // todo 向隊列添加元素

    /***
     * 向隊列添加元素
     * @param ele 要添加的元素
     */
    public void insert(int ele){
        // 判斷隊列是否已滿
        if (isFull()){
            System.out.println("隊列已滿!");
            return;
        }
        // 插入元素,隊尾後移
        this.data[rear] = ele;
        rear = (rear+1) % maxSize;
    }
    // todo 從隊列取出元素

    /***
     * 從隊列取出元素
     * @return 取出的元素
     */
    public int remove(){
        // 判斷隊列是否為空
        if (isEmpty()){
            throw new RuntimeException("隊列為空");
        }
        // 傳回隊首資料,隊首後移
        int remove = this.data[front];
        front = (front+1) % maxSize;
        return remove;

    }
    // todo 顯示隊列中所有元素

    /***
     * 顯示隊列中所有元素
     */
    public void list(){
        List<Integer> collect = Arrays.stream(this.data).boxed().collect(Collectors.toList());
        if (rear < front){
            System.out.println(collect.subList(0,rear));
            System.out.println(collect.subList(front,maxSize));
        }else {
            System.out.println(collect.subList(front,rear));
        }

    }
    // todo 顯示隊列首元素

    /***
     * 顯示隊列首元素
     * @return 隊列首元素
     */
    public int first(){
        // 判斷隊列是否為空
        if (isEmpty()){
            throw new RuntimeException("隊列為空");
        }
        return this.data[front];
    }
}
           

繼續閱讀