算法與數(shù)據(jù)結(jié)構(gòu) : 棧的實現(xiàn)及運用

本文是在閱讀《算法》第四版時的筆記温亲。

棧數(shù)據(jù)結(jié)構(gòu)遵循 LIFO( last in first out ) 的原則菇怀。
它主要有壓棧和彈棧這兩種操作以及 isEmpty()size() 函數(shù)快鱼。

LIFO

關(guān)于 LIFO 原則麻献,有一個很好的例子:假如你有一堆郵件在桌子上(這堆郵件就是一個棧結(jié)構(gòu)),有新郵件的時候世落,你會把新郵件放在這一堆郵件的最上面,這個操作就是壓棧糟需,新郵件總是處于棧頂屉佳,而你要處理這些郵件的時候,會從最上面的開始讀洲押,也就是從棧頂開始一封一封的讀武花,讀過的郵件,就從這堆郵件里面拿出來杈帐,這就是彈棧髓堪,彈棧總是對棧頂?shù)臄?shù)據(jù)進行操作娘荡。

Java實現(xiàn)一個簡單的棧結(jié)構(gòu)

書上目前沒看見關(guān)于 Stack 具體實現(xiàn)的代碼干旁,所以我也是只基于數(shù)組實現(xiàn)了 Stack 的基本功能,有不對的地方炮沐,請指正争群,謝謝!4竽辍换薄!
這里主要是實現(xiàn)四個方法:

  • Stack() 定義一個棧
  • push(T t) 壓棧
  • pop() 彈棧
  • isEmpty() 判斷棧是否為空
  • size() 返回棧內(nèi)數(shù)據(jù)個數(shù)
public class Stack<T> implements Iterable<T> {
    @Override
    public Iterator<T> iterator() {
        return null;
    }
    private ArrayList<T> array = new ArrayList<T>();
    public Stack(){
    }
    public void push(T t){
        this.array.add(t);
    }
    public T pop(){
        return this.array.remove(array.size()-1);
    }
    public boolean isEmpty(){
        return this.array==null;
    }
    public int size(){
        return this.array.size();
    }
}

棧的運用

引用《算法》第四版里的例子。

先看一個數(shù)學(xué)表達式:

( 1 + ( 2 + 3 ) * ( 4 * 5 ) ) )

這個數(shù)學(xué)表達式翔试,學(xué)過小學(xué)數(shù)學(xué)的都知道計算結(jié)果是 101 轻要。
我們把上面的表達式輸入到計算機里面,輸入的是字符串垦缅,要怎樣處理冲泥,它才能得出 101 這個結(jié)果呢?

上世紀(jì) 70 年代壁涎,E.W.Dijkstra 運用兩個棧結(jié)構(gòu)解決了這個問題凡恍,一個棧 ( ops ) 用來保存操作符(+,-怔球,*嚼酝,/,sqrt )竟坛,一個棧 ( vals ) 用來保存操作數(shù)(數(shù)字)闽巩,同時還得遵循下面這幾種原則:

  • 輸入表達式的時候钧舌,操作數(shù)和操作符要用一個空格隔開。
  • 忽略左括號
  • 遇見右括號涎跨,棧 ops 彈出一個操作符延刘,棧 vals 彈出必要的操作數(shù),然后將計算結(jié)果再壓棧操作壓入棧 vals 六敬。

看著有點玄幻碘赖,本人還買的英文版,對英語沒過四級的我來說就更玄幻了外构,不急普泡,看代碼。

public class Evalution {
    public static void main(String[] args) {
        Stack<String> ops = new Stack<String>();
        Stack<Double> vals = new Stack<Double>();
        while (!StdIn.isEmpty()) {
            String s = StdIn.readString();
            if (s.equals("("));
            else if (s.equals("+")) ops.push(s);
            else if (s.equals("-")) ops.push(s);
            else if (s.equals("*")) ops.push(s);
            else if (s.equals("/")) ops.push(s);
            else if (s.equals("sqrt")) ops.push(s);
            else if (s.equals(")")) {
                String op = ops.pop();
                double v = vals.pop();
                if (op.equals("+")) v = vals.pop() + v;
                else if (op.equals("-")) v = vals.pop() - v;
                else if (op.equals("*")) v = vals.pop() * v;
                else if (op.equals("/")) v = vals.pop() / v;
                else if (op.equals("sqrt")) v = Math.sqrt(v);
                vals.push(v);
            }
            else vals.push(Double.parseDouble(s));
        }
        StdOut.println(vals.pop());
    }
}

首先审编,你會發(fā)現(xiàn)在 while 循環(huán)的條件里面亂入了一個 StdIn 撼班,別慌,這是《算法》作者自己封裝的一個工具類垒酬,這本書里面還用到其他的一些作者自己封裝的工具類砰嘁,在這里 (https://introcs.cs.princeton.edu/java/stdlib/) 可以下載到。

接下來勘究,emmm...矮湘,while 循環(huán)的判斷語句這里有點問題,因為這段代碼運行下來口糕,輸入上面的數(shù)學(xué)表達式之后缅阳,會死循環(huán),很驚喜景描,很意外十办,反正網(wǎng)上說是停止符 EOF 這些的問題,可是我是來學(xué)算法的超棺,這些問題不管向族,有網(wǎng)友說輸入上面的數(shù)學(xué)表達式之后回車,然后 Ctrl + D 就可以了棠绘,試了一下件相,行得通。弄唧。适肠。

代碼邏輯分析

好了終于到了最重要的環(huán)節(jié),來分析一下這段代碼的邏輯吧候引,搞懂了其實挺簡單的,然而我花了一些時間才搞懂敦跌。澄干。逛揩。。

嗯麸俘,每一次循環(huán)辩稽,都會讀取一個操作數(shù)或者操作符,這里可能會問 sqrt 怎么處理的(其實是我自己問的)从媚,在上面就說過逞泄,操作數(shù)和操作符,用空格隔開拜效,這樣才不會出錯喷众,其實也是因為 Scanner 類的邏輯,這里不討論紧憾。

讀取到一個操作符到千,就是一層層的 if...else if..else... 判斷了,如果是左括號就跳過本次循環(huán)赴穗,執(zhí)行下一次循環(huán)憔四,如果是其他的操作符(比如 + ,- )般眉,就將操作符壓入棧 ops 了赵,如果不是操作符,而是操作數(shù)甸赃,就壓入棧 vals 斟览。

上的各種壓棧理清楚了,是不是發(fā)現(xiàn)當(dāng)遇見右括號的時候辑奈,畫風(fēng)就變了苛茂,是的,這是最重要的一步(個人認(rèn)為)鸠窗,因為妓羊,這里就是進行計算的邏輯,嗯稍计,到這里建議再看看前面實現(xiàn) Stack 的彈棧和壓棧的代碼邏輯躁绸。

這一步可能圖解更好,但是書上的圖拍下來不清晰臣嚣,有時間畫了再補上來净刮。開始分析之前,再把數(shù)學(xué)表達式搬過來:

( 1 + ( 2 + 3 ) * ( 4 * 5 ) ) )

就拿遇見的第一個右括號舉例硅则,此時淹父,棧 ops 里面有兩個元素( +,+ )怎虫,棧 vals 里面有三個元素( 1暑认,2困介,3 ),遇見右括號蘸际,ops 彈棧座哩,拿到棧頂元素操作符 + ,然后 vals 彈棧粮彤,拿到棧頂操作數(shù) 3 根穷,此時兩個棧都經(jīng)過了一次彈棧, ops 和 vals 的棧頂元素分別是 +2 导坟,再看代碼屿良,又是一串 if 判斷語句,并且是利用 ops 的彈棧彈出的元素做判斷條件乍迄,而 操作數(shù)棧管引,又得彈棧一次,此時 vals 經(jīng)歷了兩次彈棧闯两,彈出的數(shù)據(jù)分別是 32褥伴,然后這兩個數(shù)據(jù)進行相應(yīng)的算數(shù)操作,再將兩個數(shù)算數(shù)操作后得出的結(jié)果壓入棧 vals 漾狼,這個時候就相當(dāng)于是 2 + 3 這一段現(xiàn)在用 5 代替重慢。

隨著 while 的再次循環(huán),再遇見右括號逊躁,還是進行相同的彈棧壓棧操作似踱,最后棧 ops 為空,棧 vals 里面只有一個數(shù)稽煤,這個數(shù)就是最后的計算結(jié)果核芽,這個數(shù)學(xué)表達式,就成功的得出了結(jié)果酵熙。

思考

經(jīng)過上面的不專業(yè)的瞎BB轧简,我發(fā)現(xiàn)這段代碼好像只適合小括號里面只有兩個操作數(shù)的情況,要是把 ( 2 + 3 ) 改成 ( 2 + 3 +6 )匾二,得到的結(jié)果是 182.0 哮独,而不是 221 ,那么察藐,要怎么改善一下皮璧,才能避免這種情況呢,我也是寫到這里才想起來這個問題分飞,沒有代碼實現(xiàn)悴务,說說我現(xiàn)在的想法,我覺得不忽略左括號浸须,將左括號壓入 ops 棧惨寿,然后遇見右括號的時候邦泄,ops 就的彈棧直到遇見右括號删窒,這只是個大概的思路裂垦。。肌索。蕉拢。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市诚亚,隨后出現(xiàn)的幾起案子晕换,更是在濱河造成了極大的恐慌,老刑警劉巖站宗,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闸准,死亡現(xiàn)場離奇詭異,居然都是意外死亡取董,警方通過查閱死者的電腦和手機磨隘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門靶累,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人库快,你說我怎么就攤上這事≡客纾” “怎么了义屏?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蜂大。 經(jīng)常有香客問我闽铐,道長,這世上最難降的妖魔是什么奶浦? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任兄墅,我火速辦了婚禮,結(jié)果婚禮上财喳,老公的妹妹穿的比我還像新娘察迟。我一直安慰自己,他們只是感情好耳高,可當(dāng)我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布扎瓶。 她就那樣靜靜地躺著,像睡著了一般泌枪。 火紅的嫁衣襯著肌膚如雪概荷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天碌燕,我揣著相機與錄音误证,去河邊找鬼继薛。 笑死,一個胖子當(dāng)著我的面吹牛愈捅,可吹牛的內(nèi)容都是我干的遏考。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼蓝谨,長吁一口氣:“原來是場噩夢啊……” “哼灌具!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起譬巫,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤咖楣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后芦昔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體诱贿,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年咕缎,在試婚紗的時候發(fā)現(xiàn)自己被綠了珠十。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡锨阿,死狀恐怖宵睦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情墅诡,我是刑警寧澤壳嚎,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站末早,受9級特大地震影響烟馅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜然磷,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一郑趁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧姿搜,春花似錦寡润、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至致份,卻和暖如春变抽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工绍载, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留诡宗,地道東北人。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓击儡,卻偏偏與公主長得像塔沃,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子曙痘,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容