Java數據結構和算法(五)——隊列

隊列。queue,就是現實生活中的排隊。java


一、簡單隊列:算法

public class Queqe {
    private int array[];
    private int front;
    private int end;
    private int number;
    private int max;
    
    private Queqe(int maxsize){
        array = new int[maxsize];
        max = maxsize;
        front = 0;
        end = 0;
        number = 0;
    }
    
    private void insert(int item){
        if(isFull()){
            System.out.println("is full,can not insert");
            return;
        }
        array[end++] = item;
        number++;
    }
    
    private int remove(){
        if(isEmpty()){
            System.out.println("is empty,can not remove");
            return -1;
        }
        number--;
        return array[front++];
    }
    
    private boolean isFull(){
        return number == max;
    }
    private boolean isEmpty(){
        return number == 0;
    }
    
    private int size(){
        return number;
    }
    
    private int peekFront(){
        return array[front];
    }
    
    public static void main(String[] args) {
        Queqe q = new Queqe(4);
        System.out.println("queqe is empty:"+q.isEmpty());
        
        q.insert(1);
        q.insert(2);
        q.insert(3);
        q.insert(4);
        q.insert(5);
        
        System.out.println(q.size());
        System.out.println("front is "+q.peekFront());
        
        while(!q.isEmpty())
            System.out.println(q.remove());
    }
}

result:
queqe is empty:true
is full,can not insert
4
front is 1
1
2
3
4

仍是經過數組實現,但是和棧不一樣的是。隊列的話有隊頭隊尾。隊頭指向隊列的首部。而隊尾指向隊列的尾部。number爲隊列中數的個數,每當插入一個新元素。隊尾後移。每當移除一個新元素,隊首後移,插入和移除的同一時候依據隊列是否爲空或者是滿,才進行插入和移除

先進的元素排在前面,那麼移除的時候就是先移除隊頭,達到先進先出的效果。·插入和移除並不用移動整個數組,僅僅需改變隊頭和隊列的指向,因此時間複雜度和棧同樣都是O(1)。express


二、不用number以後的方法改變
數組

前面用了number統計隊列中元素個數,事實上不用這個變量。單靠隊頭和隊尾也是可以實現隊列。數據結構


    private boolean isFull(){
        return end == max;
    }
    private boolean isEmpty(){
        return (front ==0&&end ==0)||front == max;
    }
    
    private int size(){
        return end -front;
    }

隊尾減去隊頭就是元素的個數。因爲一旦插入,end是添加1的。

而推斷是否是滿了更簡單,隊尾移到數組尾部便是滿了。數據結構和算法

空的話會複雜一些,一種是一開始front爲零,但是有元素插入,此時end不爲零。假設二者爲零那就是空了。還有就是不停remove以後,front移到最後,證實以前的元素全部remove掉了,此時也爲空。post


做者依據的是front和end的變化。而後再insert和remove中直接改變front和end的值,在isEmpty和isFull中,好比在isFull()中:spa

    private boolean isFull(){
        return end+2 == front||(front+max-2==end);
    }

做者的end一開始設爲-1,而後一旦end超過max會變成-1,因此其中有着很是複雜的位置關係。


這樣更復雜。.net

因爲這樣類似循環隊列,超出以後又重頭開始插入。code

事實上在isEmpty和isFull中直接進行推斷就可以了。

而後真的超出的時候直接打印錯誤後return。


三、優先級隊列

銀行辦業務固然要排隊,但是。銀行的vip用戶不需要,因爲他存的錢比你多。銀行重視這種客戶。優先級高,因此他儘管比你晚來到銀行。但是排號的時候拿到的號比你還前。


那這種話,優先級隊列就像是一開始就依據優先級排列好順序的隊列。

private void insert(int item){
    if(isFull()){
        System.out.println("is full,can not insert");
        return;
    }
    if(end == 0){
        array[end++] = item;
    }else{
        int i;
        for ( i = number-1; i >=0; i--) {
            if(item > array[i]){
                array[i+1] = array[i];
            }
        }
        array[i+1]= item;
        end++;
    }
    number++;
}

result:
queqe is empty:true
size:0
is full,can not insert
queqe is empty:false
size:4
front is 4
4
3
2
1 

現在咱們將數值大的當作是優先級高的,第一個插入直接插入數組第一位,後面插入的開始比較,假設比前面的數都小,那麼就放在隊列最後面,假設大的話,就將整個隊列後推,而後找到適當的位置插入。和插入排序是類似的。

這樣插入元素的同一時候,就已經依照優先級從大到小的順序排好序了(前:prefix expression 中:infix expression 後:postfix expression)。


四、算術表達式的解析

1+2+3=?  

因爲咱們從小接受的教育就是從左到右,有括號計算括號中面,先乘除後加減這種思路。而後看到上面那個算式的時候一會兒就得出結果,這是中綴表達式。

也就是咱們腦裏面計算算式的方式。


從左到右,1+2看後面,是+號。那可以直接算1+2的值爲3,3+3後面是=號了,直接計算3+3=6。


1+2*3=?

從左到右,1+2看後面,是*號,那不能直接算1+2的值,先計算2*3=6。再看後面爲=。因此計算1+6=7。


1*(2+3)=?

從左到右,1後面是*,因此原本先計算的,但是後面是(因此先看括號,括號中面是2+3=5後面是=,因此直接計算1*5=5。


但是計算機並不像人腦這麼聰明。一眼看過去基本可以心算。計算機認後綴表達式比較easy,假設咱們從小就接受的是後綴表達式的方式的話。那對於咱們來講同樣可以。


後綴表達式的話就用符號a,b,c表示了。因爲多位數字的話,寫成1242132+,根本就不知道是那兩個數字相加,那麼就要有分隔符,但是無疑會添加難度。

a+b-c轉後綴:

讀a。讀到+,繼續讀到b,寫成ab。再讀到-號可以將+放在ab後面。即ab+,讀入c,後面結束了則ab+c-。


a+b*c轉後綴:

讀a,讀+,讀b,放置爲ab,再讀後面,*優先級大於+號。臨時不能放+,再讀c,c後面結束。因此可以放入*,在放+。即abc*+。


a*(b+c)轉後綴:

讀a,讀*,後面發現(不能放置*,(裏比*優先級高,讀b+c,後面爲),可變爲bc+,再和a*合。即abc+*。


這篇儘管講得是隊列。但是要用到的結構是棧,因爲進來進去的。這裏的算數不用壓入棧,直接輸出。

a+b-c轉後綴:

直接輸出a。讀+。棧空壓入棧,再輸出b。棧非空。彈出+,讀到-,+優先級>= -,輸出+,壓-入棧,輸出c,結束了,彈出-。

最後結果:ab+c-。


a+b*c轉後綴:

直接輸出a,讀+。棧空壓入棧,再輸出b,棧非空,彈出+,讀到*,+優先級< -。因此先+壓入棧,再壓*,輸出c,結束了,彈出*,再彈+。

最後結果:abc*+。


a*(b+c)轉後綴:

直接輸出a。讀*。棧空壓入棧。讀到(壓(入棧,輸出b,讀+。壓入棧。輸出c。讀),發現後面結束可以彈出+並輸出。彈出(不輸出,彈出*。

最後結果:abc+*。


看了這個分析過程以後,就是利用棧,對操做符進行棧的壓入和彈出。


假設純粹用高級語言寫計算器,直接使用中綴表達式就能夠,但是到了底層的編譯器。就是需要後綴表達式實現。還要考慮到位數和其它操做符,可想代碼遠遠比上面的複雜。

整體的思路就是這樣,代碼的實現就是經過棧和條件推斷進行入棧和出棧就能夠。


0
1
 
 
相關文章
相關標籤/搜索