【棧和隊列】定義一個類,實現一個隊列,隊列裏有兩個棧,此類支持隊列的基本操作

功能需求

        在一個類中,定義兩個公共訪問的棧,這兩個棧通過交互形成一個隊列,保持先進先出的特點並且支持入棧add、poll、peek的操作。同時算法複雜度不能太高。

詳細解析

        棧的特點是先進後出,而隊列的特點是先進先出,我們把兩個棧首尾相接起來,一個壓入棧,一個彈出棧,就可以實現相應的隊列的操作。具體實現是定義一個壓入棧stackPush,在壓入數據時只往這個棧中壓入數據和一個退出棧stackPop彈出數據只從這個棧中彈出,分別對應隊列的入列和出列。

        因爲數據壓入棧的時候,順序是先進後出的。那麼只要吧stackPush的數據在壓入stackPop中,順序就變了回來。例如,將1~5依次壓入stackPush棧中,那麼在stackPush棧中棧頂到棧底依次爲5~1,將此時的5~1倒入stackPop中,那麼stackPop棧中從棧頂到棧底的數據就會依次是1~5.再從stackPop彈出時,就會像隊列一樣,其效果圖如下

 

        這樣看起來是非常簡單的,實際上的要求將會有以下兩點:1、stackPush中的數據必須要一次性全部壓入stackPop中;2、如果stackPop棧中已經存在元素數據,是不能給stackPop棧中壓入數據的。這兩點都是會導致錯誤的。

        如果違反了1原則:舉個例子,1~5依次壓入stackPush,stackPush棧頂到棧底的元素分別爲5~1,從stackPush壓入stackPop棧中時,只將棧頂的5和4壓入stackPop,stackPush棧還有3,2,1三個元素存在沒有壓入。此時用戶想要彈棧操作,那麼4將先被彈出。這樣與預想的隊列順序就不一致了。

        如果違反了規則2:將1-5依次壓入stackPush棧中,stackPush棧中從棧頂到棧底依次爲5~1,stackPush棧中的元素全部倒入stackPop棧中壓棧處理,所以stackPop棧中的元素從棧頂到棧底依次爲1~5,又在此時壓入6~10到stackPush,stackPop不爲空,stackPush不能將其數據壓入stackPop。如果違反了強行壓入,那麼stackPop棧中從棧頂到棧低的元素就會變爲6~10,1~5,那麼此時再彈出棧中元素就會把6先彈出棧,不符合隊裏的規則。

        在調用add(), poll(),peek三種方法中任何一種發生時"壓入"元素時的行爲都是可以的,前提條件是不違反以上兩點。具體請看以下代碼:

代碼實現

package com.hekaikai666.test2;

import java.util.Stack;

/**
 * 
 * @author hekaikai666
 * @time 2018年8月23日下午8:40:35
 **/
public class StackTo {
    // 棧一存儲數據
    private Stack<Integer> stackPush;
    // 棧二存儲棧一中出來的數據
    private Stack<Integer> stackPop;

    /**
     * 單例模式實例化棧(構造方法)
     */
    public StackTo() {
	super();
	this.stackPush = new Stack<Integer>();
	this.stackPop = new Stack<Integer>();
    }

    /**
     * poll()方法操作棧中數據
     */
    public int poll() {
	// 判斷兩個棧是否都爲空
	if (stackPop.isEmpty() && stackPush.isEmpty()) {
	    // 拋出一個運行時異常
	    throw new RuntimeException("Your Stack is empty");
	    // 如果只有存入棧爲空
	} else if (stackPop.isEmpty()) {
	    // 循環彈出stackPush中的元素並壓入stackPop棧中,知道stackPush棧爲空
	    while (!stackPush.isEmpty()) {
		stackPop.push(stackPush.pop());
	    }
	}
	// 返回此棧值
	return stackPop.pop();
    }
    public int peek() {
	// 判斷兩個棧是否都爲空
	if (stackPop.isEmpty() && stackPush.isEmpty()) {
	    // 拋出一個運行時異常
	    throw new RuntimeException("Your Stack is empty");
	    // 如果只有存入棧爲空
	} else if(stackPop.isEmpty()) {
	    // 循環彈出stackPush中的元素並壓入stackPop棧中,知道stackPush棧爲空
	    while (!stackPush.isEmpty()) {
		stackPop.push(stackPush.pop());
	    }
	}
	// 返回此棧值
	return stackPop.peek();
    }
}

總結分析

        我們都能想到兩個先進先出的棧首尾相接能實現一個隊列,但是在這兩個棧中的細節,比如說他們要是沒有完全彈出元素,那麼會導致棧種元素混亂,之後就不符合隊列的要求了,其實實現很簡單,思想很重要

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