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


前言

棧和隊列是算法的一個基本的知識點之一。這篇文章主要介紹三道有關棧和隊列的算法題。因為篇幅所限,只介紹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;
    }
}

 


 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM