线性结构-堆栈

<big>编译环境:python v3.5.0, mac osx 10.11.4</big>

什么是堆栈

  • 具有一定约束的线性表,只在一段(栈顶)进行操作
  • 后入先出(LIFO),如同叠碗:先叠上的,最后才会被取出来


  • 插入数据(Push,入栈),删除数据(Pop,出栈)

堆栈的抽象数据类型描述

  • 图解堆栈

堆栈的顺序存储(数组)实现

  • 基本结构实现(下载地址:stack.py
    # -- coding: utf-8 --
    class Stack():
    def init(self, maxSize): # 初始化堆栈,设定最大值
    self._stack = []
    self._maxSize = maxSize
    self._p = -1 # 指针指向栈顶
    def push(self, value): # 插入数据
    if self._p >= self._maxSize-1: # 通过判断指针位置是否超过初始容量,确定堆栈是否满了
    print('stack is full')
    else:
    self._stack.append(value)
    self._p += 1 # 指针向栈顶移动
    print('push %d in stack ' % value)
    def pop(self): # 删除数据
    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 # 返回最后一位元素的值

  • 堆栈的改良应用(下载地址:stack_apply.py
    怎样利用数组存储两个堆栈,要求最大化的利用数组空间,即只要任何一个堆栈不空,就能储存元素
    解决方案:<big>两个堆栈从数组两端往中间生长</big>,即一个初始指针指向-1,另一个堆栈初始指针指向maxSize,当两指针相邻时,则两堆栈都满了。


    # -- coding: utf-8 --

      class newStack():
          def __init__(self, maxSize):
              self._maxSize = maxSize
              self._p1 = -1  # 堆栈1 的指针
              self._p2 = maxSize  # 堆栈2 的指针
              self._stack = [None] * maxSize  # 储存元素的数组
    
          def push(self, value, tag):  # 插入数据, tag表示插入哪一个堆栈堆栈
              if self._p2 - self._p1 == 1:  # 通过判断两个指针位置是否相邻,确定堆栈是否满了
                  print('all stack are full')
              else:
                  if tag == 1:
                      self._p1 += 1  # 指针向中间移动
                      self._stack[self._p1] = value
                      print('push %d in stack1 ' % value)
                  elif tag == 2:
                      self._p2 -= 1  # 指针向中间移动
                      self._stack[self._p2] = value
                      print('push %d in stack2 ' % value)
                  else:
                      print("stack %d doesn't exist" % tag)
    
          def pop(self, tag):  # 删除数据
              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)
    

堆栈的链式存储(链表)实现

由于堆栈的链式存储结构实际上是一个单向链表,所以栈顶指针应该指向链表的表头,若是指向表尾的话,当pop出一个元素后,我们无法得知这个元素的前一个元素是什么。

  • 基本结构实现(下载地址:stack_chain.py
    class stackChain():
    def init(self, value=None, next=None): # 创建一个空链表
    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  # 指针指向头一个元素
                    print('pop '+str(p.value)+' out from stack')
                    stack_chain.next = p.next  # 将指针指向栈顶元素
                    element = p.value
                    del p  # 释放空间
                return element
    
  • 链式堆栈的应用(下载地址:stack_expression.py
    表达式求值,应用堆栈实现后缀表达式的求值过程,即将中缀表达式转化为后缀表达式
    解决方案:用列表存储输出状态,用堆栈储存表达符号。


    # -- coding: utf-8 --

      import stack_chain
    
      def expression(expressionStrings):  # 输入表达式字符串,如:'1 + 1 * 2'以空格空开
           allexpress = ['+', '-', '*', '/', '(', ')']
           orderEX = {  # 构建运算符优先级
           '(': [1,0],  # 第一位为优先级,第二位为标签
           ')': [1],
           '+': [3],
           '-': [3],
           '*': [2],
           '/': [2],
           }
           output = []  # 建立存放输出的列表
           p_expression = stack_chain.stackChain()  # 建立存放表达式的堆栈
           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]:  # 栈顶优先级低,则输出栈顶元素
                            if topElement == '(' and orderEX['('][1] == 0:  # 未弹出'(',将'('不断输入
                                stack_chain.push(p_expression, topElement)
                                stack_chain.push(p_expression, element)
                                break
                            elif topElement == ')':  # 遇到 ')'则改变'('的标签
                                orderEX['('][1] = 1
                            elif topElement == '(':
                                orderEX['('][1] = 0  # 当'('被pop出来后,初始化'('的标签
                            else:
                                output.append(topElement)
                        else:  # 如果新扫到的运算符优先级低,则插入堆栈,并跳出循环
                                stack_chain.push(p_expression, topElement)  # 将栈顶元素重新插入
                                stack_chain.push(p_expression, element)  # 将新运算符也插入
                                break
                   if stack_chain.isEmpty(p_expression):  # 如果堆栈为空,则说明元素没有push进去
                         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
    

堆栈的其他应用:

  • 函数的调用及递归实现
  • 深度优先搜索
  • 回溯算法

源代码: JacobKam-GitHub

后续内容:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容

  • (数据结构与算法总是联系在一起) -数据结构简介 eg:图书摆放 新书的插入与旧书的查取(随便放:新书插入方便、但...
    Spicy_Crayfish阅读 838评论 0 0
  • 编译环境:python v3.5.0, mac osx 10.11.4 前述内容: 线性表 队列 堆栈 线性结构...
    掷骰子的求阅读 2,417评论 1 7
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young阅读 3,776评论 1 10
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,124评论 29 470
  • 史上最全的iOS面试题及答案 iOS面试小贴士———————————————回答好下面的足够了----------...
    Style_伟阅读 2,345评论 0 35