线性结构-堆栈

1. 什么是堆栈

·LIFO,后进先出,只在栈顶(Top)插入删除元素
·数据对象集:一个有0个或多个元素的有穷线性表
·操作集:

  1. 创建空栈 Stack
  2. 判断空 is_empty
  3. 长度,返回栈的元素数量 len
  4. 压入 push
  5. 弹出 pop
  6. 访问栈顶元素 top

2.栈的实现

2.1 栈的顺序表实现

后端插入和删除是O(1)操作,表尾作栈顶

PS:与C语言不同,python中的list类可以自动扩大存储区,所以不会出现栈满的情况

class StackUnderflow(ValueError):
    pass

class SStack():
    
    def __init__(self):
        self._elems = []
        
    def is_empty(self):
        return self._elems == []
    
    def __len__(self):
        return len(self._elems)
    
    def push(self,elem):
        self._elems.append(elem)
        
    def pop(self):
        if self._elems == []:
            raise StackUnderflow("in SStack.pop()")
        return self._elems.pop()
    
    def top(self):
        if self._elems == []:
            raise StackUnderflow("in SStack.pop()")
        return self._elems[-1]

2.2栈的链表实现

前端插入和删除是O(1)操作,表头作栈顶

PS:虽然顺序表即可满足绝大部分的实际需要,但是扩大存储需要做一次高代价的复制操作,以及完整的大块存储区,而链接技术在这方面较有优势

class Node():
    def __init__(self,elem,next_=None):
        self._elems = elem
        self._next = next_
    
    def __str__(self):
        return str(self._elems)
    
class LStack():
    
    def __init__(self):
        self._head = None
        self._lenth = 0
        
    def __len__(self):
        return self._lenth
    
    def is_empty(self):
        return self._head is None
    
    def push(self,elem):
        self._head = Node(elem,self._head)
        
    def pop(self):
        if self._head is None:
            raise StackUnderflow("in LStack.pop()")
        p = self._head
        self._head = p._next
        return p.elem
    
    def top(self):
        if self._head is None:
            raise StackUnderflow("in LStack.top()")
        return self._head.elem
    
# 栈实现颠置
list1 = list(range(10))
st1 = SStack()
for x in list1:
    st1.push(x)
list2 = []
while not st1.is_empty():
    list2.append(st1.pop())
print(list2)

3栈的应用

3.1 表达式的变换和计算

思路

# 后缀表达式的计算

def suf_exp_evaluator(line):
    exp = line.split()
    operators = "+-*/"
    st = SStack()
    
    for x in exp:  # x为数字时
        if x not in operators:
            st.push(float(x))
            continue
            
        if len(st) < 2:  # x 为运算符时,要求栈内元素数量至少为2
            raise SyntaxError("Short of operands")
        a = st.pop()
        b = st.pop()
        
        # 注意b与a的运算顺序
        if x == '+':
            c = b+a
        elif x == '-':
            c = b-a
        elif x == '*':
            c = b*a
        elif x == '/':
            c = b/a
        else:
            break
            
        st.push(c)
        
    if len(st) == 1:
         return st.pop()
    else:
        raise SyntaxError("Extra operands")
        
#try:
line = input('Suffix Expression:')
#    if line == "end":
#        return
result = suf_exp_evaluator(line)
print(result)
# except Exception as ex:
   # print("Error:",type(ex),ex.args)
def trans_infix_suffix(line):
   """将中缀表达式转换为后缀表达式"""
   priority = {"(":1,"+":3,"-":3,"*":5,"/":5}
   operators = "+-*/()"
   
   st = SStack()
   exp = []  # 储存后缀表达式
   
   for x in token(line):  # 生成器
       if x not in operators:
           exp.append(x)
       elif st.is_empty() x == '(':
           st.push(x)
       elif x == ')':
           while not st.is_empty() and st.top != '(':
               exp.append(st.pop())
           if st.is_empty():
               raise SyntaxError("Missing '(' .")
           st.pop() #弹出左括号,右括号也不进栈
       else:
           while (not st.is_empty() and priority[st.top()] >= priority[x]):
               exp.append(st.pop())
           st.push(x)
               
   while not st.is_empty():
       if st.top() == '(':
           raise SyntaxError("Extra '('")
       exp.append(st.pop())
           
   return exp

def token(line):
   """逐一生成line中的一个个项"""
   i, llen = 0, len(line)
   operators = "+-*/()"
   while i< llen:
       while i < llen and line[i].isspace():  # 若i为空格,跳过
           i += 1

       if i >= llen:
           break
       if line[i] in operators:
           yield line[i]
           i += 1
           continue

       j = i+1

       while (j<llen and not line[j].isspace() and line[j] not in operators):
           if ((line[j]=='e' or line[j]=='E') and line[j+1] == '-'):
               j += 1
           j += 1

       yield line[i:j]
       i=j

3.2 栈与递归:背包问题

递归:在一个定义中引用了被定义的对象本身。

递归调用的过程 可以 视为向栈里压入元素的过程

递归返回的过程 可以 视为不断取出栈元素的过程

背包问题
一个背包里可放入重量为weight的物品,现有n件物品的集合S,其中物品的重量分别为w0,w1,…,wn-1。问能否选出若干件物品,重量之和正好等于weight。如果存在,该问题就有解。

# hint: n件物品的问题,可以归结为两个n-1件物品的问题。任意子问题有解,原问题就有解
def knap_rec(weight,wlist,n):
    # 出口
    if weight == 0:
        return True
    if weight<0 or (weight>0 and n<1):
        return False
    # 递归主题
    if knap_rec(weight-wlist[n-1],wlist,n-1):   # 如果选择最后一件物品
        print("Item "+str(n)+":",wlist[n-1])
        return True
    if knap_rec(weight,wlist,n-1):   # 如果不选择最后一件物品
        return True
    else:
        return False
    
wlist = [3,9,2,31,13,28,11,6,40]
a = knap_rec(50,wlist,9)
a
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值