线性数据结构:一旦某个元素被添加进来,它与前后元素的相对位置将保持不变。
真正区分线性数据结构的是元素的添加方式和移除方式,尤其是添加操作和移除操作发生的位置。
1、栈
栈有时也被称作“下推栈”。它是有序集合,添加操作和移除操作总发生在同一端。这种排序被称作LIFO,即后进先出。
用Python实现栈
class Stack:
# 创建一个空栈。它不需要参数,且会返回一个空栈
def __init__(self):
self.items = []
# 检查栈是否为空。它不需要参数,且会返回一个布尔值
def isEmpty(self):
return self.items == []
# 将一个元素添加到栈的顶端,它需要一个参数item,且无返回值
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)
用栈实现数制转换
在计算机科学中,经常涉及数制转换,比如将十进制转换为二进制,方法就是用该数除以2并记录余数,最后反转余数顺序即可得到对应的二进制数据。这里记录余数并反转输出非常适合栈的处理方式。
def divideBy2(decNumber):
# 创建空栈用于存放余数
remstack = Stack()
# 用该数除以2,将余数存入栈,商降为0之前继续循环
while decNumber > 0:
rem = decNumber % 2
remstack.push(rem)
decNumber = decNumber // 2
binString = ""
# 将栈内的数值依次弹出并拼接在一起
while not remstack.isEmpty():
binString = binString + str(remstack.pop())
return binString
将2换为参数,就能将十进制数转换为任意进制数
def baseConverter(decNumber, base):
# 创建空栈
remstack = Stack()
digits = "0123456789ABCDEF"
while decNumber > 0:
rem = decNumber % base
remstack.push(rem)
decNumber = decNumber // base
newString = ''
while not remstack.isEmpty():
newString = newString + digits[remstack.pop()]
return newString
2、前序、中序、后序表达式
对于A * B这样的算式,运算符在数值中间,这种表达式被称作中序表达式,也是大家所熟悉的算式。与之对应的,运算符在数值前面的称之为前序表达式,在数值后面的是后序表达式。
中序表达式 | 前序表达式 | 后序表达式 |
---|---|---|
A + B | + A B | A B + |
A + B * C | + A * B C | A B C * + |
(A + B) * C | * + A B C | A B + C * |
A + B * C + D | + + A * B C D | A B C * + D + |
( A + B ) * (C + D) | * + A B + C D | A B + C D + * |
A * B + C * D | + * A B * C D | A B * C D * + |
A + B + C + D | + + + A B C D | A B + C + D + |
将中序表达式转换为后续表达式的步骤:
(1)创建用于保存运算符的空栈opstack,以及一个用于保存结果的空列表。
(2)使用字符串方法split将输入的中序表达式转换为一个列表。
(3)从左到右扫描这个标记列表
- 如果标记是操作数,将其添加到结果列表的末尾。
- 如果标记是左括号,将其压入opstack。
- 如果标记是右括号,反复从opstack栈中移除元素,直到移除对应的左括号。将从栈中取出的每一个运算符都添加到结果列表的末尾。
- 如果标记是运算符,将其压入opstack栈中。但是,在这之前,需要先从栈中取出优先级更高或相同的运算符,并将它们添加到结果列表的末尾。
(4)当处理完输入表达式以后,检查opstack。将其中所有剩下的运算符全部添加到结果列表的末尾。
代码实现:
from pythonds.basic import Stack
import string
def infixToPostfix(infixexpr):
prec = {}
prec["*"] = 3
prec["/"] = 3
prec["+"] = 2
prec["-"] = 2
prec["("] = 1
opStack = Stack()
postfixList = []
tokenList = infixexpr.split()
for token in tokenList:
if token in string.ascii_uppercase:
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)
3、计算后序表达式
假设后序表达式是一个以空格分隔的标记串,其中,运算符标记有*、/、+和-,操作数标记是一位的整数值,结果是一个整数。步骤如下:
(1)创建空栈operandStack
(2)使用字符串split将输入的后序表达式转换为一个列表
(3)从左往右扫描这个标记列表
- 如果标记是操作数,将其转换成整数并且压入operandStack栈中。
- 如果标记是运算符,从operandStack栈中取出两个操作数。第一次取出右操作数,第二次取出左操作数。进行相应的算数运算,然后将运算结果压入operandStack栈中。
(4)当处理完输入表达式时,栈中的值就是结果,将其从栈中返回。
代码如下:
def postfixEval(postfixExpr):
operandStack = Stack()
tokenList = postfixExpr.split()
for token in tokenList:
if token in '0123456789':
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