常用数据结构——栈 (python)

常用数据结构——栈 (python)

本科学过c++的数据结构了,但研究生转无线通信后就忘的差不多了,现在重新复习下栈。

栈(stack)、队列(queues)、双端队列(deques)和列表都是有序数据容器,元素添加后在容器内的位置跟其他元素添加和删除的顺序有关,像这样的容器被称作线性数据结构(linear data structure)。
栈可以想象为只有一端开口的瓶子,假设每放一个东西进去都会把前面放的完全盖住,那么这时你想取出最里面的东西显然是不可能的,所以你只能把上面的一个个拿出来才能取到你想要的,这就叫做后进先出(LIFO, last-in first-out)。

1. 栈的主要方法及实现

栈的方法主要有下面几种:

  • Stack() creates a new stack that is empty. It needs no parameters and returns an empty stack.
  • push(item) adds a new item to the top of the stack. It needs the item and returns nothing.
  • pop() removes the top item from the stack. It needs no parameters and returns the item. The stack is modified.
  • peek() returns the top item from the stack but does not remove it. It needs no parameters. The stack is not modified.
  • isEmpty() tests to see whether the stack is empty. It needs no parameters and returns a boolean value.
  • size() returns the number of items on the stack. It needs no parameters and returns an integer.
    在python中是没有栈的实现的,所以栈需要自己实现,简单点可以用个list充当下,更一般的要实现上面各种方法还是面向对象创造一个类比较好,实现代码如下所示:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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)

2. 栈的主要应用

2.1 字符串反转

那么,费尽心机创造一个栈有啥用呢?首先可以用来翻转字符串,当然python有超级多方式可以反转字符串,最简单的自然是string[::-1]。

1
2
3
4
5
6
7
8
def stringReverse(self, stringstring):
s = Stack()
output = ""
for ss in stringstring:
s.push(ss)
while not s.isEmpty():
output = output + s.pop()
return output

2.2 简单括号匹配

除此之外,还有简单的括号匹配问题,也可以利用栈的特性来解决:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def parChecker(symbolString):
s = Stack()
balanced = True
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

其实吧,也可以不用栈解决呀(不是我杠,笔试时间也是很重要的)

1
2
3
4
5
6
7
8
9
def parChecker(symbolString):
left = 0
right = 0
for s in symbolString:
if s == '(':
left+=1
else:
right+=1
return left==right

2.3 多重括号匹配

拓展到更复杂一点的括号匹配问题——多重括号匹配:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def parChecker(symbolString):
s = Stack()
balanced = True
index = 0
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 balanced and s.isEmpty():
return True
else:
return False

def matches(open,close):
opens = "([{"
closers = ")]}"
return opens.index(open) == closers.index(close)

当然,我又“杠”了,主要不想想这么复杂的结构2333:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def parChecker(symbolString):
l1,l2,l3,r1,r2,r3=0,0,0,0,0,0
for s in symbolString:
if s=='{':
l1+=1
elif s=='}':
r1+=1
elif s=='(':
l2+=1
elif s==')':
r2+=1
elif s=='[':
l3+=1
else:
r3+=1
return [l1,l2,l3]==[r1,r2,r3]

2.4 将十进制数转换为各种进制

想将10进制数(Decimal)转换为2进制(Binary)、8进制(Octal)或者16进制(Hexidecimal),就将这个数不断除进制数,然后将余数逆序输出,不想贴图了自己百度查下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def baseConverter(decNumber,base):
digits = "0123456789ABCDEF"
remstack = Stack()

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.5 中缀表达式、前后缀表达式

接下来就是栈的重点操作了(就是比较复杂一点)。
什么是中缀表达式呢?就是一般的表达式,比如A+B, C*D等。
顾名思义,前缀表达式就是操作符在前面,后缀就是在后面,给几个例子体会一下:
Infix Expression Prefix Expression Postfix Expression
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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 "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)

假如直接给你一个后缀表达式让你计算呢,这就是需要再写一个算法了,不过比较简单,贴上来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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

栈就目前学完了,后续有的话还会补充。

# Stack
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×