python3堆栈_Python3 栈的实现

Python 实现栈¶

栈的抽象数据结构¶

栈是有序的LIFO(后进先出)。

栈的操作有:

Stack() 创建新的空栈。

push(item) 添加新项到栈顶部。

pop() 删除栈顶项并返回栈顶项的值。栈被修改。

peek() 返回栈顶部项。不修改栈。

isEmpty() 测试栈是否为空,返回 Bool 值。

size() 返回栈长度(栈中 item 数量)。

利用列表实现栈¶

In [1]:

class Stack:

def __init__(self):

self.items = []

def isEmpty(self):

return self.items == []

def push(self, item):

self.items.append(item)

def pop(self):

return self.items.pop()

def peek(self):

return self.items[-1]

def size(self):

return len(self.items)

if __name__ == '__main__':

s = Stack()

print(s.isEmpty())

s.push(4)

s.push('dog')

print(s.peek())

s.push(True)

print(s.size())

print(s.isEmpty())

s.push(8.4)

print(s.pop())

print(s.pop())

print(s.size())

True

dog

3

False

8.4

True

2

简单括号匹配¶

区分括号是否匹配的能力是识别很多编程语言结构的重要部分。具有挑战的是如何编写一个算法,能够从左到右读取一串符号,并决定符号是否平衡。为了解决这个问题,我们需要做一个重要的观察。从左到右处理符号时,最近开始符号必须与下一个关闭符号相匹配(见 Figure 1)。此外,处理的第一个开始符号必须等待直到其匹配最后一个符号。结束符号以相反的顺序匹配开始符号。他们从内到外匹配。这是一个可以用栈解决问题的线索。

3.6.%E7%AE%80%E5%8D%95%E6%8B%AC%E5%8F%B7%E5%8C%B9%E9%85%8D.simpleparcheck.png

Figure 1

In [2]:

def parChecker(symbol_sring):

s = Stack()

balanced = True

index = 0

while index < len(symbol_sring) and balanced:

symbol = symbol_sring[index]

if symbol == '(':

s.push(symbol)

else:

if s.isEmpty():

balanced = False

else:

s.pop()

index += 1

if balanced and s.isEmpty():

return True

else:

return False

print(parChecker('((()))'))

print(parChecker('((()'))

True

False

注:栈是处理括号匹配极好的数据结构

In [8]:

def check(strings):

s = Stack()

for string in strings:

if string == '(':

s.push(string)

elif string == ')':

try:

s.pop()

except IndexError:

return False

else:

return False

return s.isEmpty()

print(check('((()))'))

print(check('()))'))

True

False

符号匹配¶

上面的两个程序仅用于'()'的匹配,实际上 Python 中常用的括号有 { } [ ] ( )。符号字符串如:

{ { ( [ ] [ ] ) } ( ) }

[ [ { { ( ( ) ) } } ] ]

[ ] [ ] [ ] ( ) { }

都是正确的匹配。

In [12]:

def check(strings):

s = Stack()

for string in strings:

if string in '{[(':

s.push(string)

elif string in ')]}':

try:

match(open=s.pop(), close=string)

except(IndexError, ValueError):

return False

else:

return False

return s.isEmpty()

def match(open, close):

opens = '{[('

closers = '}])'

if opens.index(open) != closers.index(close):

raise ValueError

print(check('[][][](){}'))

print(check('[{()]'))

True

False

进制转换¶

首先看看 Python3 内置函数进制转换用法

bin(x) oct(x) hex(x)

In [15]:

help(bin)

Help on built-in function bin in module builtins:

bin(number, /)

Return the binary representation of an integer.

>>> bin(2796202)

'0b1010101010101010101010'

In [16]:

bin(256)

Out[16]:

'0b100000000'

注:二进制字符串以0b开头

In [17]:

oct(256)

Out[17]:

'0o400'

注:八进制字符串以0o开头

In [18]:

hex(256)

Out[18]:

'0x100'

注:十六进制字符串以0x开头

int([number | string[, base]])

# 其他进制 to 十进制

In [28]:

int(bin(256), 2)

Out[28]:

256

In [29]:

int(oct(256), 8)

Out[29]:

256

In [30]:

int(hex(256), 16)

Out[30]:

256

其他进制转换¶

其他进制转换可以以十进制为媒介

In [31]:

bin(int(oct(256), 8)) # oct2bin

Out[31]:

'0b100000000'

Python3 实现十进制 to 其他进制¶

基本思想是将十进制数不断迭代除以2,并跟踪余数。Figure2 以二进制为例,展示了栈是解决这个问题的数据结构。

3.8.%E5%8D%81%E8%BF%9B%E5%88%B6%E8%BD%AC%E6%8D%A2%E6%88%90%E4%BA%8C%E8%BF%9B%E5%88%B6.figure5.png

Figure2

In [45]:

class Stack:

def __init__(self):

self.items = []

def isEmpty(self):

return self.items == []

def push(self, item):

self.items.append(item)

def pop(self):

return self.items.pop()

def peek(self):

return self.items[-1]

def size(self):

return len(self.items)

def __iter__(self):

for i in self.items[::-1]:

yield i

def box(dec_number, base=2):

remstack = Stack()

base_num = [str(i) for i in range(10)] + [chr(x) for x in range(ord('A'), ord('A')+6)]

prefix = 'box'

while dec_number > 0:

index = dec_number % base

remstack.push(base_num[index])

dec_number = dec_number // base

try:

return '0'+ prefix[[2, 8, 16].index(base)] + ''.join(remstack)

except ValueError:

return ''.join(remstack)

# test

print(box(233, 2))

print(box(233,3))

print(box(233,5))

print(box(233,8))

print(box(233,10))

print(box(233,16))

0b11101001

22122

1413

0o351

233

0xE9

注:box()函数实现十进制至2到16之间任意进制转换,但是除bin, oct, hex 外均无前缀。

中缀、前缀和后缀表达式¶

我们平常的算术表达式一般是中缀表达式,例如:A+B*C 就是中缀表达式:运算符在操作数之间。

但是如何辨别运算顺序即优先级是个问题。我们可以用括号来明确:(A+(B*C))。

其实,我们可以用前缀表达式:+ A * B C,运算符在操作数前面紧邻;

利用后缀表达式:A B C * +。

这样一来,运算符的优先级很容易体现:紧邻的运算符优先级高。

3.9.%E4%B8%AD%E7%BC%80%E5%90%8E%E7%BC%80%E5%92%8C%E5%90%8E%E7%BC%80%E8%A1%A8%E8%BE%BE%E5%BC%8F.table2.png

3.9.%E4%B8%AD%E7%BC%80%E5%90%8E%E7%BC%80%E5%92%8C%E5%90%8E%E7%BC%80%E8%A1%A8%E8%BE%BE%E5%BC%8F.table4.png

下面讨论中缀转后缀表达式,基本思想是:

创建一个名为 opstack 的空栈以保存运算符。给输出创建一个空列表。

通过使用字符串方法拆分将输入的中缀字符串转换为标记列表。

从左到右扫描标记列表。

如果标记是操作数,将其附加到输出列表的末尾。

如果标记是左括号,将其压到 opstack 上。

如果标记是右括号,则弹出 opstack,直到删除相应的左括号。将每个运算符附加到输出列表的末尾。

如果标记是运算符,*,/,+或 - ,将其压入 opstack。但是,首先删除已经在 opstack 中具有更高或相等优先级的任何运算符,并将它们加到输出列表中。

当输入表达式被完全处理时,检查 opstack。仍然在栈上的任何运算符都可以删除并加到输出列表的末尾。

3.9.%E4%B8%AD%E7%BC%80%E5%90%8E%E7%BC%80%E5%92%8C%E5%90%8E%E7%BC%80%E8%A1%A8%E8%BE%BE%E5%BC%8F.figure9.png

In [58]:

import re

def infix2postfix(infixexpr):

#确定优先级

prec = {}

prec['('] = 1

prec['+'] = 2

prec['-'] = 2

prec['*'] = 3

prec['/'] = 3

opstack = Stack() # 存储运算符

postfix_list = [] # 后缀表达式

token_list = [i for i in infixexpr if not re.match(r'\s+',i)]

for token in token_list:

if re.match(r'[0-9a-zA-Z]', token):

postfix_list.append(token) # 操作数加入后缀表达式

elif token == '(':

opstack.push(token) # '(' 压入栈内

elif token == ')':

top_token = opstack.pop()

while top_token != '(':

postfix_list.append(top_token)

top_token = opstack.pop()

else:

while (not opstack.isEmpty()) and (prec[opstack.peek()] >= prec[token]):

postfix_list.append(opstack.pop())

opstack.push(token)

while not opstack.isEmpty():

postfix_list.append(opstack.pop())

return ' '.join(postfix_list)

print(infix2postfix("A * B + C * D"))

print(infix2postfix("( A + B ) * C - ( D - E ) * ( F + G )"))

A B * C D * +

A B + C * D E - F G + * -

后缀表达式求值¶

基本思想如下图:

3.9.%E4%B8%AD%E7%BC%80%E5%90%8E%E7%BC%80%E5%92%8C%E5%90%8E%E7%BC%80%E8%A1%A8%E8%BE%BE%E5%BC%8F.figure10.png

In [61]:

def postfix_eval(postfix_expr):

s = Stack()

token_list = postfix_expr.split()

for token in token_list:

if re.fullmatch(r'([0-9])|([1-9][0-9]+)', token):

s.push(int(token))

else:

opra2 = s.pop()

opra1 = s.pop()

result = do_math(token, opra1, opra2)

s.push(result)

return s.pop()

def do_math(op, op1, op2):

if op == "*":

return op1 * op2

elif op == "/":

return op1 / op2

elif op == "+":

return op1 + op2

else:

return op1 - op2

print(postfix_eval('7 8 + 3 2 + /'))

3.0

zxzhu 2018/2/12

Reference:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值