一.算法分析:
- Python常用的数据结构:
- List列表数据常用的操作性能:
(1)列表增长可以使用append和 “+”,但是前者执行时间是O(1),后者是O(n+k)其中k是被追加的列表长度。(因为+号相当于是把两个列表复制到了一个列表中)
(2)性能比较:
首先介绍一下常用的计时模块:最普通的:time.time(),但是通常需要循环执行函数几次才能计上时。高级一点的timeit模块的Timer对象
(3)这张List操作性能表总结的很不错!!!
(4) 作出图可发现pop()是常数,pop(0)是线性增长的趋势
(5)字典操作的性能表
List与dict的in操作对比:字典的执行时间与规模无关是常数,而列表的执行时间则随着列表的规模扩大而线性上升。
二. 基本结构之线性结构:
1. 常见的线性结构:Stack、Queue、Deque(双端队列)、List
3.栈的应用:
(1)简单的括号匹配:
# 代码实现:
from pythonds.basic.stack import Stack
def parChecker(symbolString):
s = Stack()
balanced = 0
index = 0
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 balanced and s.isEmpty():
return True
else:
return False
print(parChecker('((()))'))
更多种类的括号匹配:穿插在一起或数量不对则出错
上面的代码加以修改就可以成为通用的括号匹配算法。核心思想个人认为主要是:match函数的设计判断是不是括号相匹配再弹栈、symbol in的判断方式(python的优点–类似Java的contains)
(2)十进制与二进制转化:
特征是次序反转,可以联想到栈!
# 代码实现:十进制转二进制
from pythonds.basic.stack import Stack
def divideBy2(decNumber):
remstack = Stack()
while decNumber > 0 :
rem = decNumber % 2
remstack.push(rem)
decNumber = decNumber // 2
binString = ""
while not remstack.isEmpty():
binString = binString + str(remstack.pop())
return binString
print(divideBy2(42))
下面继续代码升级!扩充到十进制转十六进制以下蔼的任意进制
这时我们需要思考的是:构造出来一个适配的字符表,弹栈时候可以由索引确定字符
(3)表达式的转化:
首先最常用的是中缀表达式和全括号表达式,然后又衍生出前缀和后缀表达式
算法:
下面我们探讨一下通用的中缀转后缀的算法:由于算术符号有优先级可能产生反转次序输出,可以考虑使用栈。简而言之就是:在从左到右逐个字符扫描中缀表达式的过程中,采用一个栈来暂存未处理的操作符。这样栈顶的操作符就是最近暂存进去的,当遇到 一个新操作符就需要跟栈顶的操作符比较一下优先级,再行处理
代码实现:
from pythonds.basic.stack import Stack
def infixToPostfix(infixerpr): # 记录操作符优先级
prec = {}
prec["*"] = 3
prec["/"] = 3
prec["+"] = 2
prec["-"] = 2
prec["("] = 1
opStack = Stack()
postfixList = []
tokenList = infixexpr.split() # 解析表达式到单词列表
# 操作数 、( 、 )
for token in tokenList :
if token in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" or token in "0123456789" :
postfixList.append(token)
elif token == '(':
opStack.push(token)
elif token == ')':
topToken = opStack.pop()
while topToken != '(':
postfixList.append(topToken)
topToken = opStack.pop()
# 操作符
else:
while (not opStack.isEmpty()) and (prec[opStack.peek()] >= prec[token]):
postfixList.append(opStack.pop())
opStack.push(token)
while not opStack.isEmpty():
postfixList.append(opStack.pop)
return " ".join(postfixList)
(4)后缀表达式求值:
代码实现:
def postfixEval(postfixExpr):
operandStack = Stack()
tokenList = postfixExpr.split()
for token in tokenList:
# 操作数
if token in "01233456789":
operandStack.push(int(token))
# 操作符
else:
operand2 = operandStack.pop() # 先出了的是后一个操作数
operand1 = operandStack.pop()
result = doMath(token,operand1,operand2)
operandStack.push(result)
return operandStack.pop()
def doMath(op,op1,op2):
if op =="*":
return op1 * op2
elif op =="/":
return op1 / op2
elif op =="+":
return op1 + op2
else:
return op1 - op2