1.什么是线性结构?
-
生活中的线性结构
-
线性结构的称呼
-
不同线性结构的关键区别在于数据项增减的方式。有的结构只允许数据项从一端添加,而有的结构则允许数据项从两端移除。
-
4个最简单但功能强大的线性结构 :栈Stack,队列Queue,双端队列Deque和列表List。
2.栈抽象数据类型及Python实现
-
一种有次序的数据项集合,在栈中,数据项的加入和移除都仅发生在同一端.这一端叫栈“顶top”,另一端叫栈“底base”.
-
生活中的栈(在顶部放书或者取走书)
-
次序:后进先出LIFO
距离栈底越近的数据项,留在栈中的时间就越长;而最新加入栈的数据项会被最先移除。
-
抽象数据类型“栈”定义为如下的操作
1)Stack():创建一个空栈,不包含任何数据项
2)push(item):将item加入栈顶,无返回值
3)pop():将栈顶数据项移除,并返回,栈被修改
4)peek():“窥视”栈顶数据项,返回栈顶的数据项但不移除,栈不被修改
5)isEmpty():返回栈是否为空栈
6)size():返回栈中有多少个数据项 -
抽象数据类型Stack操作案例
-
用Python实现ADT Stack
将ADT Stack实现为Python的一个Class;将ADT Stack的操作实现为Class的方法;由于Stack是一个数据集(结构),所以可以采用Python 的原生数据集来实现,我们选用列表 List来实现。
-
实现方法一
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[len(self.items) - 1]
def size(self):
return len(self.items)
- 测试代码
from pythonds.basic.stack import Stack
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
- 实现方法二
- 栈顶首端的版本(左),其 push/pop(insert(0,item)、pop(0))的复杂度为O(n)
- 栈顶尾端的实现 (右),其push/pop(append(item)、pop())的复杂度为O(1)
3. 栈的应用:简单括号匹配
- 括号的使用必须遵循 “平衡”规则:
首先,每个开括号要恰好对应一个闭括号;其次,每对开闭括号要正确的嵌套:
- 构造括号匹配识别算法
从左到右扫描括号串,最后打开的左括号,应该匹配最先遇到的右括号;这样,第一个左括号(最早打开),就应该匹配最后一个右括号(最后遇到)。 这种次序反转的识别,正好符合栈的特性。
- 流程图
- 代码
from pythonds.basic.stack import Stack
def parChecker(symbolString):
s = Stack()
index = 0
balanced = True
while index < len(symbolString) and balanced:
symbol = symbolString[index]
if (symbol == '('):
s.push(symbol)
else:
if s.isEmpty():
balanced = False
else:
s.pop()
index = index + 1
if s.isEmpty() and balanced:
return True
else:
return False
print(parChecker("((()))"))
print(parChecker("(()"))
-
更多括号的匹配
在实际的应用里,我们会碰到更多种括号
如python中列表所用的方括号“[]”
字典所用的花括号“{}”
元组和表达式所用的圆括号“()”
-
代码
from pythonds.basic.stack import Stack
def parChecker(symbolString):
s = Stack()
index = 0
balanced = True
while index < len(symbolString) and balanced:
symbol = symbolString[index]
if (symbol in '({['):
s.push(symbol)
else:
if s.isEmpty():
balanced = False
else:
top = s.pop()
if not matches(top, symbol):
balanced = False
index = index + 1
if s.isEmpty() and balanced:
return True
else:
return False
def matches(open, close):
if '({['.index(open) == ')}]'.index(close):
return True
else:
return False
print(parChecker("((([])))"))
4.十进制转化为二进制
-
二进制是计算机原理中最基本的概念,作为组成 计算机最基本部件的逻辑门电路,其输入和输出均仅为两种状态:0和1
十进制是0~9这十个数字字符
-
十进制数除以2 的余数从高位到低位写出来就是二进制数
-
除以2”的过程,得到的余数是从低到高的次序,而输出则是从高到低,所以需要一个栈来反转次序
-
代码
from pythonds.basic.stack import Stack
def divideBy2(decNumber):
remstack = Stack()
while decNumber > 0:
rem = decNumber % 2
remstack.push(rem)
decNumber = decNumber // 2 # //代表整数除法
symbol = ''
while not remstack.isEmpty():
symbol = symbol + str(remstack.pop())
return symbol
print(divideBy2(42))
- 十进制转化为二进制的方法扩展到更多进制同样适用
- 十进制转化为16进制以下任意代码
def baseConverter(decNumber,base):
digits = '0123456789ABCDEF'
remstack = Stack()
while decNumber>0:
rem = decNumber%base
remstack.push(rem)
decNumber = decNumber // base # //代表整数除法
symbol = ''
while not remstack.isEmpty():
symbol = symbol+digits[remstack.pop()]
return symbol
5.表达式转换
常见表达式:
- 中缀表达式:B+C
- 前缀表达式:+BC
- 后缀表达式:BC+
表达式转换
- 符号和两个操作数连在一起时,他们是一起执行的,比如*BC,则B乘以C是在一起的
中缀转后缀算法
-
-
代码
def infixToPostfix(infixexpr):
prec = {}
prec['/'] = 3
prec['*'] = 3
prec['+'] = 2
prec['-'] = 2
prec['('] = 1
optStack = Stack()
postfixList = []
tokenList = infixexpr.split()
for token in tokenList:
if token in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' or token in '0123456789':
postfixList.append(token)
elif token == '(':
optStack.push(token)
elif token == ')':
top = optStack.pop()
while top != '(':
postfixList.append(token)
top = optStack.pop()
else:
while not optStack.isEmpty() and prec[optStack.peek()] >= prec[token]:
postfixList.append(optStack.pop())
optStack.push(token)
while not optStack.isEmpty():
postfixList.append(optStack.pop())
return "".join(postfixList)
infixToPostfix("A * B + C * D")
6.后缀表达式求值
-
-
代码
def postfixEval(postfixExpr):
optStack = Stack()
tokenList = postfixExpr.split()
for token in tokenList:
if token in '0123456789':
optStack.push(int(token))
else:
num2 = optStack.pop()
num1 = optStack.pop()
res = doMath(token, num1, num2)
optStack.push(res)
return optStack.pop()
def doMath(opt, num1, num2):
if opt == '*':
return num1 * num2
elif opt == '/':
return num1 / num2
elif opt == '+':
return num1 + num2
else:
return num1 - num2
postfixEval("7 8 + 3 2 + /")