線性結(jié)構(gòu)-堆棧

<big>編譯環(huán)境:python v3.5.0, mac osx 10.11.4</big>

什么是堆棧

  • 具有一定約束的線性表,只在一段(棧頂)進(jìn)行操作
  • 后入先出(LIFO),如同疊碗:先疊上的,最后才會(huì)被取出來


  • 插入數(shù)據(jù)(Push,入棧)站超,刪除數(shù)據(jù)(Pop,出棧)

堆棧的抽象數(shù)據(jù)類型描述

  • 圖解堆棧

堆棧的順序存儲(chǔ)(數(shù)組)實(shí)現(xiàn)

  • 基本結(jié)構(gòu)實(shí)現(xiàn)(下載地址:stack.py
    # -- coding: utf-8 --
    class Stack():
    def init(self, maxSize): # 初始化堆棧,設(shè)定最大值
    self._stack = []
    self._maxSize = maxSize
    self._p = -1 # 指針指向棧頂
    def push(self, value): # 插入數(shù)據(jù)
    if self._p >= self._maxSize-1: # 通過判斷指針位置是否超過初始容量,確定堆棧是否滿了
    print('stack is full')
    else:
    self._stack.append(value)
    self._p += 1 # 指針向棧頂移動(dòng)
    print('push %d in stack ' % value)
    def pop(self): # 刪除數(shù)據(jù)
    if self._p == -1: # 通過判斷指針位置來確定堆棧是否為空
    print("it's an empty stack")
    else:
    iterms = self._stack[self._p] # 將最后一位元素的值取出
    del self._stack[self._p] # s刪除元素
    self._p -= 1 # 指針指向棧頂
    print('pop %d out' % items)
    return iterms # 返回最后一位元素的值

  • 堆棧的改良應(yīng)用(下載地址:stack_apply.py
    怎樣利用數(shù)組存儲(chǔ)兩個(gè)堆棧乖酬,要求最大化的利用數(shù)組空間死相,即只要任何一個(gè)堆棧不空,就能儲(chǔ)存元素
    解決方案:<big>兩個(gè)堆棧從數(shù)組兩端往中間生長(zhǎng)</big>剑刑,即一個(gè)初始指針指向-1,另一個(gè)堆棧初始指針指向maxSize,當(dāng)兩指針相鄰時(shí)双肤,則兩堆棧都滿了施掏。


    # -- coding: utf-8 --

      class newStack():
          def __init__(self, maxSize):
              self._maxSize = maxSize
              self._p1 = -1  # 堆棧1 的指針
              self._p2 = maxSize  # 堆棧2 的指針
              self._stack = [None] * maxSize  # 儲(chǔ)存元素的數(shù)組
    
          def push(self, value, tag):  # 插入數(shù)據(jù), tag表示插入哪一個(gè)堆棧堆棧
              if self._p2 - self._p1 == 1:  # 通過判斷兩個(gè)指針位置是否相鄰,確定堆棧是否滿了
                  print('all stack are full')
              else:
                  if tag == 1:
                      self._p1 += 1  # 指針向中間移動(dòng)
                      self._stack[self._p1] = value
                      print('push %d in stack1 ' % value)
                  elif tag == 2:
                      self._p2 -= 1  # 指針向中間移動(dòng)
                      self._stack[self._p2] = value
                      print('push %d in stack2 ' % value)
                  else:
                      print("stack %d doesn't exist" % tag)
    
          def pop(self, tag):  # 刪除數(shù)據(jù)
              if tag == 1:
                  if self._p1 == -1:  # 通過判斷指針位置來確定堆棧是否為空
                      print("it's an empty stack1")
                  else:
                      iterm1 = self._stack[self._p1]  # 將最后一位元素的值取出
                      self._stack[self._p1] = None  # 刪除元素
                      self._p1 -= 1  # 指針指向棧頂
                      print('pop %d out from stack 1' % iterm1)
                      return iterm1  # 返回最后一位元素的值
              elif tag == 2:
                  if self._p2 == self._maxSize:  # 通過判斷指針位置來確定堆棧是否為空
                      print("it's an empty stack2")
                  else:
                      iterm2 = self._stack[self._p2]  # 將最后一位元素的值取出
                      self._stack[self._p2] = None  # 刪除元素
                      self._p2 += 1  # 指針指向棧頂
                      print('pop %d out from stack 2' % iterm2)
                      return iterm2  # 返回最后一位元素的值
              else:
                  print("stack %d doesn't exist" % tag)
    

堆棧的鏈?zhǔn)酱鎯?chǔ)(鏈表)實(shí)現(xiàn)

由于堆棧的鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)實(shí)際上是一個(gè)單向鏈表,所以棧頂指針應(yīng)該指向鏈表的表頭茅糜,若是指向表尾的話七芭,當(dāng)pop出一個(gè)元素后,我們無法得知這個(gè)元素的前一個(gè)元素是什么蔑赘。

  • 基本結(jié)構(gòu)實(shí)現(xiàn)(下載地址:stack_chain.py
    class stackChain():
    def init(self, value=None, next=None): # 創(chuàng)建一個(gè)空鏈表
    self.value = value
    self.next = next

          def isEmpty(stack_chain):  # 判斷堆棧是否為空
                return stack_chain.next is None
    
          def push(stack_chain, element):  # 向堆棧stack_chain中插入元素element,并返回頭指針
                newChain = stackChain(element) # 生成新的鏈表元素
                newChain.next = stack_chain.next  # 將原表頭棧頂元素接到新元素的下面
                stack_chain.next = newChain  # 將頭指針指向新元素
                print('push '+str(element)+' in stack')
                return stack_chain
    
          def pop(stack_chain):  # 堆棧stack_chain的頭元素,并返回頭指針
                if isEmpty(stack_chain):
                    print('it is an empty stack')
                else:
                    p = stack_chain.next  # 指針指向頭一個(gè)元素
                    print('pop '+str(p.value)+' out from stack')
                    stack_chain.next = p.next  # 將指針指向棧頂元素
                    element = p.value
                    del p  # 釋放空間
                return element
    
  • 鏈?zhǔn)蕉褩5膽?yīng)用(下載地址:stack_expression.py
    表達(dá)式求值狸驳,應(yīng)用堆棧實(shí)現(xiàn)后綴表達(dá)式的求值過程,即將中綴表達(dá)式轉(zhuǎn)化為后綴表達(dá)式
    解決方案:用列表存儲(chǔ)輸出狀態(tài)缩赛,用堆棧儲(chǔ)存表達(dá)符號(hào)耙箍。


    # -- coding: utf-8 --

      import stack_chain
    
      def expression(expressionStrings):  # 輸入表達(dá)式字符串,如:'1 + 1 * 2'以空格空開
           allexpress = ['+', '-', '*', '/', '(', ')']
           orderEX = {  # 構(gòu)建運(yùn)算符優(yōu)先級(jí)
           '(': [1,0],  # 第一位為優(yōu)先級(jí),第二位為標(biāo)簽
           ')': [1],
           '+': [3],
           '-': [3],
           '*': [2],
           '/': [2],
           }
           output = []  # 建立存放輸出的列表
           p_expression = stack_chain.stackChain()  # 建立存放表達(dá)式的堆棧
           normalExpression = expressionStrings.split()
           for element in normalExpression
               if not(element in allexpress):
               output.append(element)
               else:
                    while not stack_chain.isEmpty(p_expression):  # 如果堆棧不為空,則開始判斷
                        topElement = stack_chain.pop(p_expression)  # 彈出棧頂元素并賦值給topElement
                        if orderEX[topElement][0] <= orderEX[element][0]:  # 棧頂優(yōu)先級(jí)低,則輸出棧頂元素
                            if topElement == '(' and orderEX['('][1] == 0:  # 未彈出'(',將'('不斷輸入
                                stack_chain.push(p_expression, topElement)
                                stack_chain.push(p_expression, element)
                                break
                            elif topElement == ')':  # 遇到 ')'則改變'('的標(biāo)簽
                                orderEX['('][1] = 1
                            elif topElement == '(':
                                orderEX['('][1] = 0  # 當(dāng)'('被pop出來后,初始化'('的標(biāo)簽
                            else:
                                output.append(topElement)
                        else:  # 如果新掃到的運(yùn)算符優(yōu)先級(jí)低,則插入堆棧,并跳出循環(huán)
                                stack_chain.push(p_expression, topElement)  # 將棧頂元素重新插入
                                stack_chain.push(p_expression, element)  # 將新運(yùn)算符也插入
                                break
                   if stack_chain.isEmpty(p_expression):  # 如果堆棧為空,則說明元素沒有push進(jìn)去
                         stack_chain.push(p_expression, element)
          while not(stack_chain.isEmpty(p_expression)):
               topElement = stack_chain.pop(p_expression)
               if not topElement in ['(', ')']:
                   output.append(topElement)
    
          return output
    

堆棧的其他應(yīng)用:

  • 函數(shù)的調(diào)用及遞歸實(shí)現(xiàn)
  • 深度優(yōu)先搜索
  • 回溯算法

源代碼: JacobKam-GitHub

后續(xù)內(nèi)容:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市酥馍,隨后出現(xiàn)的幾起案子辩昆,更是在濱河造成了極大的恐慌,老刑警劉巖旨袒,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件汁针,死亡現(xiàn)場(chǎng)離奇詭異术辐,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)施无,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門辉词,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人猾骡,你說我怎么就攤上這事瑞躺。” “怎么了卓练?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵隘蝎,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我襟企,道長(zhǎng)嘱么,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任顽悼,我火速辦了婚禮曼振,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蔚龙。我一直安慰自己冰评,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布木羹。 她就那樣靜靜地躺著甲雅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪坑填。 梳的紋絲不亂的頭發(fā)上抛人,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音脐瑰,去河邊找鬼妖枚。 笑死,一個(gè)胖子當(dāng)著我的面吹牛苍在,可吹牛的內(nèi)容都是我干的绝页。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼寂恬,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼续誉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起初肉,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤屈芜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體井佑,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡属铁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了躬翁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片焦蘑。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖盒发,靈堂內(nèi)的尸體忽然破棺而出例嘱,到底是詐尸還是另有隱情,我是刑警寧澤宁舰,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布拼卵,位于F島的核電站,受9級(jí)特大地震影響蛮艰,放射性物質(zhì)發(fā)生泄漏腋腮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一壤蚜、第九天 我趴在偏房一處隱蔽的房頂上張望即寡。 院中可真熱鬧,春花似錦袜刷、人聲如沸聪富。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽墩蔓。三九已至,卻和暖如春萧豆,著一層夾襖步出監(jiān)牢的瞬間奸披,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工炕横, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留源内,地道東北人葡粒。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓份殿,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親嗽交。 傳聞我的和親對(duì)象是個(gè)殘疾皇子卿嘲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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