如果讓你手寫個棧和隊列,你還會寫嗎? 侵立刪

來源:程序員私房菜(ID:eson_15)

 

昨天跟一個CSDN上的朋友聊天,他說現在如果讓他自己手寫一個棧或者隊列,估計都要寫蠻久的,平時雖然都在用,但是都是別人封裝好的集合。

確實,經典的數據結構,包括排序算法,雖然我們平時不用手寫了,但是這些內功,作爲開發人員來說是必須要掌握的。受此啓發,我打算更一下經典數據結構和算法的系列文章。今天先從棧和隊列說起。

這些東西,擠地鐵時,吃飯排隊時,等公交時,可以拿來看看,或者,就把它當作個下午茶吧~

 

我們知道,在數組中,若知道數據項的下標,便可立即訪問該數據項,或者通過順序搜索數據項,訪問到數組中的各個數據項。但是棧和隊列不同,它們的訪問是受限制的,即在特定時刻只有一個數據項可以被讀取或者被刪除。衆所周知,棧是先進後出,只能訪問棧頂的數據,隊列是先進先出,只能訪問頭部數據。這裏不再贅述。

 

棧的主要機制可以用數組來實現,也可以用鏈表來實現,下面用數組來實現棧的基本操作:

 


 
  1. class ArrayStack {

  2.    private long[] a;

  3.    private int size; //棧數組的大小

  4.    private int top; //棧頂

  5.  

  6.    public ArrayStack(int maxSize) {

  7.        this.size = maxSize;

  8.        this.a = new long[size];

  9.        this.top = -1; //表示空棧

  10.    }

  11.  

  12.    public void push(long value) {//入棧

  13.        if(isFull()) {

  14.            System.out.println("棧已滿!");

  15.            return;

  16.        }

  17.        a[++top] = value;

  18.    }

  19.  

  20.    public long peek() {//返回棧頂內容,但不刪除

  21.        if(isEmpty()) {

  22.            System.out.println("棧中沒有數據");

  23.            return 0;

  24.        }

  25.        return a[top];

  26.    }

  27.  

  28.    public long pop() { //彈出棧頂內容,刪除

  29.        if(isEmpty()) {

  30.            System.out.println("棧中沒有數據!");

  31.            return 0;

  32.        }

  33.        return a[top--];        

  34.    }

  35.  

  36.    public int size() {

  37.        return top + 1;

  38.    }

  39.  

  40.    public boolean isEmpty() {

  41.        return (top == -1);

  42.    }

  43.  

  44.    public boolean isFull() {

  45.        return (top == size -1);

  46.    }

  47.  

  48.    public void display() {

  49.        for(int i = top; i >= 0; i--) {

  50.            System.out.print(a[i] + " ");

  51.        }

  52.        System.out.println("");

  53.    }

  54. }

 

數據項入棧和出棧的時間複雜度均爲O(1)。這也就是說,棧操作所消耗的時間不依賴於棧中數據項的個數,因此操作時間很短。棧不需要比較和移動操作。

隊列也可以用數組來實現,不過這裏有個問題,當數組下標滿了後就不能再添加了,但是數組前面由於已經刪除隊列頭的數據了,導致空。所以隊列我們可以用循環數組來實現,見下面的代碼:


 
  1. public class RoundQueue {

  2.    private long[] a;

  3.    private int size;   //數組大小

  4.    private int nItems; //實際存儲數量

  5.    private int front;  //頭

  6.    private int rear;   //尾

  7.  

  8.    public RoundQueue(int maxSize) {

  9.        this.size = maxSize;

  10.        a = new long[size];

  11.        front = 0;

  12.        rear = -1;

  13.        nItems = 0;

  14.    }

  15.  

  16.    public void insert(long value) {

  17.        if(isFull()){

  18.            System.out.println("隊列已滿");

  19.            return;

  20.        }

  21.        rear = ++rear % size;

  22.        a[rear] = value; //尾指針滿了就循環到0處,這句相當於下面註釋內容      

  23.        nItems++;

  24. /*        if(rear == size-1){

  25.            rear = -1;

  26.        }

  27.        a[++rear] = value;

  28. */

  29.    }

  30.  

  31.    public long remove() {

  32.        if(isEmpty()) {

  33.            System.out.println("隊列爲空!");

  34.            return 0;

  35.        }

  36.        nItems--;

  37.        front = front % size;

  38.        return a[front++];

  39.    }

  40.  

  41.    public void display() {

  42.        if(isEmpty()) {

  43.            System.out.println("隊列爲空!");

  44.            return;

  45.        }

  46.        int item = front;

  47.        for(int i = 0; i < nItems; i++) {

  48.            System.out.print(a[item++ % size] + " ");

  49.        }

  50.        System.out.println("");

  51.    }

  52.  

  53.    public long peek() {

  54.        if(isEmpty()) {

  55.            System.out.println("隊列爲空!");

  56.            return 0;

  57.        }

  58.        return a[front];

  59.    }

  60.  

  61.    public boolean isFull() {

  62.        return (nItems == size);

  63.    }

  64.  

  65.    public boolean isEmpty() {

  66.        return (nItems == 0);

  67.    }

  68.  

  69.    public int size() {

  70.        return nItems;

  71.    }

  72. }

 

和棧一樣,隊列中插入數據項和刪除數據項的時間複雜度均爲O(1)。

 

還有個優先級隊列,優先級隊列是比棧和隊列更專用的數據結構。優先級隊列與上面普通的隊列相比,主要區別在於隊列中的元素是有序的,關鍵字最小(或者最大)的數據項總在隊頭。數據項插入的時候會按照順序插入到合適的位置以確保隊列的順序。優先級隊列的內部實現可以用數組或者一種特別的樹——堆來實現。

 


 
  1. public class PriorityQueue {

  2.    private long[] a;

  3.    private int size;

  4.    private int nItems;//元素個數

  5.  

  6.    public PriorityQueue(int maxSize) {

  7.        size = maxSize;

  8.        nItems = 0;

  9.        a = new long[size];

  10.    }

  11.  

  12.    public void insert(long value) {

  13.        if(isFull()){

  14.            System.out.println("隊列已滿!");

  15.            return;

  16.        }

  17.        int j;

  18.        if(nItems == 0) { //空隊列直接添加

  19.            a[nItems++] = value;

  20.        }

  21.        else{//將數組中的數字依照下標按照從大到小排列

  22.            for(j = nItems-1; j >= 0; j--) {

  23.                if(value > a[j]){

  24.                    a[j+1] = a[j];

  25.                }

  26.                else {

  27.                    break;

  28.                }

  29.            }

  30.            a[j+1] = value;

  31.            nItems++;

  32.        }

  33.    }

  34.  

  35.    public long remove() {

  36.        if(isEmpty()){

  37.            System.out.println("隊列爲空!");

  38.            return 0;

  39.        }

  40.        return a[--nItems];

  41.    }

  42.  

  43.    public long peekMin() {

  44.        return a[nItems-1];

  45.    }

  46.  

  47.    public boolean isFull() {

  48.        return (nItems == size);

  49.    }

  50.  

  51.    public boolean isEmpty() {

  52.        return (nItems == 0);

  53.    }

  54.  

  55.    public int size() {

  56.        return nItems;

  57.    }

  58.  

  59.    public void display() {

  60.        for(int i = nItems-1; i >= 0; i--) {

  61.            System.out.print(a[i] + " ");

  62.        }

  63.        System.out.println(" ");

  64.    }

  65. }

 

這裏實現的優先級隊列中,插入操作需要 O(N) 的時間,而刪除操作則需要 O(1) 的時間。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章