死磕算法第二彈——棧、隊列、鏈表(3)

本文整理來源 《輕鬆學算法——互聯網算法面試寶典》/趙燁 編著面試

用棧實現隊列

因爲棧和隊列的特殊順序存儲結構,一些面試官會出一些題目,好比用棧實現隊列和用隊列實現棧。算法

這樣的題目在實際工做中並不具備實際應用意義,徹底是爲了考察你們的思考能力。測試

用兩個棧實現隊列

通常會用兩個棧來實現隊列。首先,咱們將這兩個棧分別定義爲stack1和stack2code

方案1
咱們讓入隊操做在stack1中執行,而出隊操做在stack2中執行。隊列

  • 入隊:直接向stack1入棧
  • 出隊:將stack1中的全部元素出棧,依次入棧到stack2中,而後彈出stack2中的stack2中的棧頂元素,接着把stack2中的全部元素出現,依次壓入stack1中。

來回入棧、出隊比較繁瑣,尤爲是出隊比較麻煩,須要先將元素從stack1倒入stack2裏,而後stack2彈出元素以後又倒回stack1裏。ci

方案2
入隊都在stack1中進行,stack2用於出隊,同時保證全部元素都在一個棧裏,且遵循如下規則:it

  • 入隊:無論stack1是否爲空棧,都將stack2中的元素壓入stack1中。
  • 出隊:若stack2不爲空棧,則直接從stack2中彈出元素;若stack2爲空棧,則把stack1中的元素倒入stack2中,再從stack2中彈出元素;若兩個棧都是空的,則說明隊列爲空隊,不能出隊。

這種思路與方案1同樣,只不過把倒回去的這個操做放在入隊時執行,卻使連續入隊、出隊的效率提升了。io

方案3
入隊都在stack1中操做,出隊在stack2中操做,同時遵循如下規則:class

  • 入隊:直接把元素壓入stack1中。
  • 出隊:若是stack2不爲空,則直接彈出stack2中的元素;若是stack2爲空,則將stack1中的是全部元素帶入stack2;若是stack2爲空,則將stack1中的全部元素倒入stack2中,而後彈出stack2中的棧頂元素。一樣若兩個棧都是空棧,則隊列爲空隊,沒法出棧。

這個方案在入隊時很是簡單,而在出隊時,多數狀況下能夠直接經過出隊stack2實現,若須要把stack1中的元素倒入stack2中,則通常不用每次都進行操做。最壞的狀況就是出隊一個元素、入隊一個元素這樣循環操做,致使每次出隊都要轉移元素。效率

三個方案的操做時同樣的。整體來講方案3是很是好的方案。

public class Stack2Queue<T> {
    private Stack<T> stack1;
    private Stack<T> stack2;
    private int maxLength;

    public Stack2Queue(int capacity) {
        maxLength = capacity;
        stack1 = new Stack<>(capacity);
        stack2 = new Stack<>(capacity);
    }

    public boolean put(T item){
        if (stack1.isFull() || maxLength == size()){
            //滿了
            return false;
        }
        stack1.push(item);
        return true;
    }

    public T poll(){
        if (!stack2.isEmpty()){
            return stack2.pop();
        }else {
            while (!stack1.isEmpty()){
                stack2.push(stack1.pop());
            }
            return stack2.pop();
        }
    }

    private int size() {
        return stack1.size() + stack2.size();
    }

}

測試代碼:

public class Stack2QueueTest {

    @Test
    public void main(){
        Stack2Queue<Integer> queue = new Stack2Queue<>(5);
        queue.put(1);
        queue.put(2);
        Assert.assertEquals(1,(int)queue.poll());
        queue.put(3);
        queue.put(4);
        Assert.assertEquals(2,(int)queue.poll());
        Assert.assertEquals(3,(int)queue.poll());
    }

}

用兩個隊列實現棧

棧的主要操做就是入棧和出棧,其特色就是後進先出。
咱們先將兩個隊列分別定義爲queue1與queue2。
方案1
入棧和出棧,都是queue1中完成,而queue2做爲中轉空間

  • 入棧:直接入queue1便可。
  • 出棧: 把queue1中除最後一個元素外的全部元素都移動到queue2中,再將queue1中的元素出隊,此時即出棧;緊接着queue2中的全部元素移動到queue1中

這種操做過程與用棧實現隊列的方案1同樣,都是把第2個結構當作一箇中轉站,而後將數據來回倒。
方案2
從方案1中能夠看到,在出棧時要把queue2中的元素移動到queue1中。在兩個隊列之間可否不用每次先出棧再把元素移動回去?

  • 入棧:兩個隊列哪一個不爲空,就把元素入隊到哪一個隊列中;若是都爲空,則任選一個隊列入隊,假設這個隊列就是queue1.
  • 出棧:把不爲空的隊列中除最後一個元素外的全部元素移動到另外一個隊列中,而後出隊最後一個元素。
public class Queue2Stack<T> {
    private ArrayQueue<T> queue1;
    private ArrayQueue<T> queue2;
    private int maxLength;

    public Queue2Stack(int capacity){
        maxLength = capacity;
        queue1 = new ArrayQueue<>(capacity);
        queue2 = new ArrayQueue<>(capacity);
    }


    /**
     * 入棧
     * @param item 入棧元素
     * @return 入棧結果
     */
    public boolean push(T item){
        if(size() == maxLength){
            return false;
        }
        //若是中轉空間爲空,能夠直接放入。當須要出棧時,放入元素即爲隊頭
        if (queue2.isEmpty()){
            queue1.put(item);
        }else {
            queue2.put(item);
        }
        return true;
    }

    /**
     * 出棧
     * @return 出棧元素
     */
    public T pop(){
        if (size() == 0){
            throw new IndexOutOfBoundsException("棧裏空了");
        }else {
            if (queue2.isEmpty()){
                while (queue1.size() > 1){
                    queue2.put(queue1.poll());
                }
                return queue1.poll();
            }else {
                while (queue2.size() > 1){
                    queue1.put(queue2.poll());
                }
                return queue2.poll();
            }
        }
    }

    private int size() {
        return queue1.size() + queue2.size();
    }
}

測試代碼:

public class Queue2StackTest {

    @Test
    public void main() {
        Queue2Stack<Integer> stack = new Queue2Stack<>(5);
        stack.push(1);
        stack.push(2);
        Assert.assertEquals(2, (int) stack.pop());
        stack.push(3);
        stack.push(4);
        Assert.assertEquals(4, (int) stack.pop());
        Assert.assertEquals(3, (int) stack.pop());
    }

}
相關文章
相關標籤/搜索