1. 程式人生 > >演算法:棧和佇列題目集合(一)

演算法:棧和佇列題目集合(一)

前言

棧和佇列是演算法的一個基本的知識點之一。這篇文章主要介紹三道有關棧和佇列的演算法題。因為篇幅所限,只介紹push和pop這兩種方法的實現
  • 用棧實現佇列
  • 用佇列實現棧
  • 迴圈佇列的實現

用棧實現佇列

入佇列的功能我們可以用棧的入棧的功能替代。但問題在於出佇列的功能怎麼實現。 這裡有一個問題,就是棧是後入先出的,佇列是先進先出的,兩者出入的方式不一樣。 那麼怎麼實現方向的一致呢? 我們可以使用兩個棧,一個棧用於輸入,一個棧用於輸出。當發現輸出棧為空的時候,把排列的資料從輸入棧一個個彈出,“倒入”到 輸出棧中,這樣的話,資料排列的方向就剛好被逆轉過來了,原本在輸入棧中處於棧底的資料被置換到輸出棧的棧頂,這時候對它出棧也就同時完成了佇列的出列的功能。   下面是具體的圖示 1.入佇列操作: 等同於對入佇列進行入棧操作,圖示如下   2.出佇列操作: 判斷當輸出棧為空時,先把輸入棧的資料依次彈出並加入到輸出棧中   步驟1   步驟2 對輸出棧棧頂進行出棧操作,即可完成出佇列功能   步驟3 具體程式碼
import java.util.Stack;

class MyQueue {
    private Stack<Integer> stack1;
    private Stack<Integer> stack2;
    private boolean isPushState = true;
    /** Initialize your data structure here. */
    public MyQueue() {
      // 輸入棧
      stack1 = new Stack<Integer>();
      // 輸出棧
      stack2 = new Stack<Integer>();
    }

    /** Push element x to the back of queue. */
    public void push(int x) {
      stack1.push(x);
    }

    public void transformStack () {
        if (stack2.empty()) {
            while (!stack1.empty()) {
                int t = stack1.pop();
                stack2.push(t);
            }
        }
    }

    /** Removes the element from in front of queue and returns that element. */
    public int pop() {
        transformStack();
        return stack2.pop();
    }

    /** Returns whether the queue is empty. */
    public boolean empty() {
      return stack1.empty() && stack2.empty();
    }
}

 


 

用佇列實現棧

這裡同樣有兩個功能需要我們實現,分別是入棧功能和出棧功能   入棧功能 我們可以用入棧操作模擬實現   出棧功能 我們又來到了關鍵功能,這時候你能猜到,我們又需要用到兩個佇列去實現這個出棧功能了 但問題在於,我們還能否通過講資料從一個佇列“倒”到另一個佇列的方式逆轉資料方向呢? 這是不行的,因為佇列先入先出的特性,導致分割後佇列的出入方向仍然是不變的。所以我們要換個思路: 一個元素入隊列了,我們接下來希望這個佇列像棧一樣通過pop把它直接彈出來,但是前面還有很多個元素排著隊呢,這時我們想,只要把前面排隊的所有元素先出列到另外一個輔助佇列裡面去,接下來不就可以直接把這個元素踢出佇列從而模擬出棧了嗎? 步驟1   步驟2 當然完成pop操作後我們還要做一件事情,就是輔助佇列和主佇列互換,以讓未來還能按同樣的流程再來一次。 具體程式碼
import java.util.LinkedList;
import java.util.Queue;

class MyStack {
    private Queue queue1;
    private Queue queue2;

    /** Initialize your data structure here. */
    public MyStack() {
        queue1 = new LinkedList<Integer>();
        queue2 = new LinkedList<Integer>();
    }

    /** Push element x onto stack. */
    public void push(int x) {
        queue1.offer(x);
    }

    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
      while (queue1.size()>1) {
          queue2.offer(queue1.poll());
      }
      int result =  (Integer) queue1.poll();
      Queue temp =queue1;
      queue1 = queue2;
      queue2 = temp;
      return result;
    }

    /** Returns whether the stack is empty. */
    public boolean empty() {
      return queue1.isEmpty();
    }
}
   

迴圈佇列的實現

設計迴圈佇列的原因 對於普通的單向佇列,在入佇列和出佇列的時候可能會遇到一種“佇列假滿”的現象,導致空間的浪費如下圖所示   所以我們要做的,就是通過設定頭部(front)和尾部(rear)兩個指標來區分佇列的“滿的部分”和“空的部分”,並且允許在填充到陣列末尾的時候,能通過回到陣列的頭部這種迴圈的方式繼續填充陣列,從而提高陣列空間的利用率。   怎麼實現從尾部到頭部的迴圈呢? 我們可以通過取餘運算子實現,因為當 i = 陣列長度- 1的時候,(i + 1) % 陣列長度 = 0,也就是說這個時候指標又從尾部回到了陣列的頭部   具體程式碼
class MyCircularQueue {
    private int [] queue;
    private int front;
    private int rear;
    private int len;
    /** Initialize your data structure here. Set the size of the queue to be k. */
    public MyCircularQueue(int k) {
      queue = new int[k+1];
      // 包含
      front = 0;
      // 不包含
      rear = 0;
      len = k+1;
    }

    /** Insert an element into the circular queue. Return true if the operation is successful. */
    public boolean enQueue(int value) {
      if (isFull()) return false;
      queue[rear] = value;
      rear =(rear+1) % len;
      return true;
    }

    /** Delete an element from the circular queue. Return true if the operation is successful. */
    public boolean deQueue() {
      if (isEmpty()) return false;
      queue[front] = -1;
      front = (front + 1) % len;
      return true;
    }

    /** Get the front item from the queue. */
    public int Front() {
        if (isEmpty()) return -1;
      return queue[front];
    }

    /** Get the last item from the queue. */
    public int Rear() {
        if (isEmpty()) return -1;
        if (rear>0) return queue[rear-1];
        else return queue[len - 1];
    }

    /** Checks whether the circular queue is empty or not. */
    public boolean isEmpty() {
        if (rear == front)  return true;
        else                return false;
    }

    /** Checks whether the circular queue is full or not. */
    public boolean isFull() {
      if ((rear + 1)%len== front) return true;
      else                return false;
    }
}

 


  &nbs