线性结构-堆栈

编译环境:python v3.5.0, mac osx 10.11.4

什么是堆栈

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


    线性结构-堆栈_第1张图片
  • 插入数据(Push,入栈),删除数据(Pop,出栈)

堆栈的抽象数据类型描述

线性结构-堆栈_第2张图片
  • 图解堆栈
    线性结构-堆栈_第3张图片

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

  • 基本结构实现(下载地址: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)
    怎样利用数组存储两个堆栈,要求最大化的利用数组空间,即只要任何一个堆栈不空,就能储存元素
    解决方案:两个堆栈从数组两端往中间生长,即一个初始指针指向-1,另一个堆栈初始指针指向maxSize,当两指针相邻时,则两堆栈都满了。

    线性结构-堆栈_第4张图片

    # -- 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)
    表达式求值,应用堆栈实现后缀表达式的求值过程,即将中缀表达式转化为后缀表达式
    解决方案:用列表存储输出状态,用堆栈储存表达符号。

    线性结构-堆栈_第5张图片

    # -- 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

后续内容:

  • 队列
  • 线性结构相关算法

你可能感兴趣的:(线性结构-堆栈)