一.中缀表达式求值
问题:
通过把“中缀转后缀”和“后缀求值”两个算法功能集成在一起(非简单的顺序调用),
实现对中缀表达式直接求值,新算法还是从左到右扫描中缀表达式,
但同时使用两个栈,一个暂存操作符,一个暂存操作数,来进行求值。
创建一个函数,接受参数为一个字符串,即一个中缀表达式,
其中每个数字或符号间由一个空格隔开;
返回一个浮点数,即求值的结果。(支持 + - * / ^ 五种运算)
其中“ / ”定义为真除True DIV,结果是浮点数类型
代码:
class Stack:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def push(self, item):
self.items.append(item)
def pop(self):
if not self.isEmpty():
return self.items.pop()
def peek(self):
return self.items[len(self.items) - 1]
def size(self):
return len(self.items)
def calculate(s) -> float:
def domath(op, op1: float, op2: float): # 运算函数,加减乘除乘方
if op == "*":
return op1 * op2
elif op == "/":
return op1 / op2
elif op == "+":
return op1 + op2
elif op == "-":
return op1 - op2
elif op == "^": # ^
return op1 ** op2
def doOperand(op): # 运算函数,计算栈内数
op2 = operandStack.pop()
op1 = operandStack.pop()
result = domath(toptoken, op1, op2)
operandStack.push(result)
prec = {"^": 4, "*": 3, "/": 3, "+": 2, "-": 2, "(": 1} # 运算符优先级
opStack = Stack() # 记录运算符号栈
operandStack = Stack() # 记录数字栈
tokenlist = s.split() # 所有符号
for token in tokenlist:
if token.isnumeric():
operandStack.push(float(token)) # 添加数字入栈
elif token == "(":
opStack.push(token) # 压入左括号
elif token == ")":
toptoken = opStack.pop() # 读取到右括号时,提出一个运算符
while toptoken != "(": # 进行计算
doOperand(toptoken)
toptoken = opStack.pop()
else: # token优先级更低时,先进行栈内的运算
while (not opStack.isEmpty()) and (prec[opStack.peek()]) >= prec[token]:
toptoken = opStack.pop()
doOperand(toptoken)
opStack.push(token)
while not opStack.isEmpty():
toptoken = opStack.pop()
doOperand(toptoken)
return operandStack.pop()
# 代码结束
结果检验
输入:
# 调用检验
print("======== 1-calculate ========")
print(calculate("( 2 + 3 ) * 6 + 4 / 2"))
print(calculate("2 ^ 3 + 4 * 5 - 16 / 2"))
print(calculate("( 5 + 1 ) * 2 / 3 - 3 ^ ( 2 + 8 / 4 ) / 9 + 6"))
输出:
======== 1-calculate ========
32.0
20.0
1.0
二.基数排序
问题:
实现一个基数排序算法,用于10进制的正整数从小到大的排序。
思路是保持10个队列(队列0、队列1…队列9、队列main),开始,所有的数都在main队列,没有排序。
第一趟将所有的数根据其10进制个位(09),放入相应的队列09,全放好后,按照FIFO的顺序,将每个队列的数合并排到main队列。
第二趟再从main队列队首取数,根据其十位的数值,放入相应队列0~9,全放好后,仍然按照FIFO的顺序,将每个队列的数合并排到main队列。
第三趟放百位,再合并;第四趟放千位,再合并。
直到最多的位数放完,合并完,这样main队列里就是排好序的数列了。
创建一个函数,接受参数为一个列表,为需要排序的一系列正整数,
返回排序后的数字列表。
代码:
class Queue:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def enqueue(self, item):
self.items.insert(0, item)
def dequeue(self):
return self.items.pop()
def size(self):
return len(self.items)
def radix_sort(s) -> list:
# 请在此编写你的代码(可删除pass语句)
main = Queue()
for n in s:
main.enqueue(n) # 全部入队main队列
nums = [Queue() for i in range(10)] # 准备十个队列
d = len(str(max(s))) # 最大数的位数
dstr = "%%0%dd" % d
for i in range(-1, -d - 1, -1): # 数字放入对应栈
while not main.isEmpty():
n = main.dequeue()
dn = (dstr % n)[i]
nums[int(dn)].enqueue(n)
for k in range(10): # 从10个队列集中到main队列
while not nums[k].isEmpty():
main.enqueue(nums[k].dequeue())
result = []
while not main.isEmpty():
result.append(main.dequeue())
return result
# 代码结束
结果检验:
输入:
# 调用检验
print("======== 2-radix_sort ========")
print(radix_sort([1, 2, 4, 3, 5]))
print(radix_sort([8, 91, 34, 22, 65, 30, 4, 55, 18]))
输出:
======== 2-radix_sort ========
[1, 2, 3, 4, 5]
[4, 8, 18, 22, 30, 34, 55, 65, 91]
三.HTML标记匹配
问题:
实现扩展括号匹配算法,用来检查HTML文档的标记是否匹配。
HTML标记应该成对、嵌套出现,
开标记是这种形式,闭标记是这种形式。
创建一个函数,接受参数为一个字符串,为一个HTML文档中的内容,返回True或False,表示该字符串中的标记是否匹配。
输入样例1:
<html> <head> <title> Example </title> </head> <body> <h1>Hello, world</h1> </body> </html>
输出样例1:
True
思路:
先分离出<>内需要匹配的内容,依次检查是否匹配
代码:
def HTMLMatch(s) -> bool:
from pythonds.basic.stack import Stack
import re
st = Stack()
def subString2(s): # 获得<>内的tag内容
rule = r'<(.*?)>'
slotList = re.findall(rule, s)
return slotList
lst = subString2(s) # 分离出需要匹配的<>中的内容
pipei = True # 初始值True
if re.search('/\w+', lst[0]) != None: # 首个tag不含/
pipei = False
else:
for token in lst:
if re.search('/\w+', token) == None: # 不含/的tag入栈
st.push(token)
else: # 发现含/的tag时,检查与栈首的tag是否匹配,若匹配则删去栈首tag
if token[1:] != st.peek():
pipei = False
break
else:
st.pop()
continue
if st.size() != 0:
pipei = False
return pipei
结果检验:
输入:
print("======== 3-HTMLMatch ========")
print(
HTMLMatch(
"<html> <head> <title>Example</title> </head> <body> <h1>Hello, world</h1> </body> </html>"
))
print(
HTMLMatch(
"<html> <head> <title> Test </title> </head> <body> <p>It's just a test.</p> <p>And this is for False.<p> </body> </html>"
))
输出:
======== 3-HTMLMatch ========
True
False
四.用链表实现栈和队列
问题:
用链表实现ADT Stack与ADT Queue的所有接口
栈Stack 有“先进后出”的特性
队列Queue 有“先进后出的特性”
代码:
先定义节点Node类:
class Node:
def __init__(self, initldata):
self.data = initldata
self.next = None
def getData(self):
return self.data
def getNext(self):
return self.next
def setData(self, newdata):
self.data = newdata
def setNext(self, newnext):
self.next = newnext
实现Stack:
class LinkStack():
def __init__(self):
self.head = None # 栈顶 head
self.length = 0
def isEmpty(self):
return self.head is None
def size(self):
return self.length
def peek(self):
return self.head.getData()
def push(self, item): # 入栈
top = Node(item) # 入栈数引入一个节点
top.setNext = (self.head) # 该节点指向head
self.head = top
self.length += 1
def pop(self): # 出栈
top_item = self.head.getData()
self.head = self.head.getNext()
self.length -= 1
return top_item
实现队列Queue:
class LinkQueue():
# 请在此编写你的代码(可删除pass语句)
def __init__(self):
self.head = None # 队首
self.tail = None # 队尾
self.length = 0
def isEmpty(self):
return self.head is None
def size(self):
return self.length
def enqueue(self, item):
tail = Node(item)
if self.head is None:
self.head = self.tail = tail # 第一个入队的情况
else: # 其他情况:队尾指向item,然后item成为新队尾
self.tail.setNext(tail)
self.tail = self.tail.getNext()
self.length += 1
def dequeue(self):
top_item = self.head.getData() # 待出队数top_item为队首
if self.head == self.tail:
self.head=self.tail=None # 队列中只有一项的情况
else:
self.head=self.head.getNext() # head 变为原head的后一项
self.length-=1
return top_item
结果检验:
输入:
# 检验
print("======== 4-Link Stack & Link Queue ========")
s = LinkStack()
q = LinkQueue()
for i in range(10):
s.push(i)
q.enqueue(i)
print(s.peek(), q.dequeue()) # 9 0
print(s.pop(), q.size()) # 9 9
while not s.isEmpty():
s.pop()
print(s.size(), q.isEmpty()) # 0 False
输出:
======== 4-Link Stack & Link Queue ========
9 0
9 9
9 False
五.实现双链无序表
问题:
实现双向链表版本的UnorderedList,接口同ADT UnorderedList
包含如下方法:isEmpty, add, search, size, remove, append,index,pop,insert, len, getitem
用于列表字符串表示的__str__方法 (注:__str__里不要使用str(), 用repr()代替
用于切片的__getitem__方法
在节点Node中增加prev变量,引用前一个节点 在UnorderedList中增加tail变量与getTail方法,引用列表中最后一个节点
选做:DoublyLinkedList(iterable) -> new DoublyLinkedList initialized from iterable’s items
选做:eq, iter
个人理解是能够实现我们通常所用列表的基本功能
代码:
这个问题需要用到二叉链表,先定义有两个指向的节点:
class Node:
def __init__(self, initldata):
self.data = initldata
self.next = None
self.prev = None
def getData(self):
return self.data
def getNext(self):
return self.next
def getPrev(self):
return self.prev
def setData(self, newdata):
self.data = newdata
def setNext(self, newnext):
self.next = newnext
def setPrev(self, newprev):
self.prev = newprev
先实现判断是否为空isEmpty,返回大小size
class DoublyLinkedList():
def __init__(self, it=None):
self.head = None
self.tail = None
self.length = 0
if it is not None: # 添加列表中的初始元素
for d in it:
self.append(d)
def isEmpty(self):
return self.head is None
def size(self):
return self.length
__len__ = size
def getTail(self):
return self.tail
实现add,append,insert:
def add(self, item): # 加为第一个
idx0 = Node(item)
if self.head is None:
self.head = self.tail = idx0 # 列表原本为空的情况
else:
self.head.setPrev(idx0) # 前一个设为idx0
idx0.setNext(self.head) # idx0后一个设为head
self.head = idx0 # 将原head更换为idx0
self.length += 1
def append(self, item): # 加为最后一个
idx_1 = Node(item)
if self.head is None:
self.head = self.tail = idx_1 # 空列表的情况
else:
self.tail.setNext(idx_1)
idx_1.setPrev(self.tail)
self.tail = idx_1
self.length += 1
def insert(self, idx, item): # 加为第idx个
current, n = self.head, 0
while n < idx:
current = current.getNext()
n += 1
if current is None: # 两种情况,idx为0或idx为列表长度,即current为列表尾
if self.head is None:
self.add(item)
else:
self.append(item)
else: # idx在中间的情况,此时current=idx
idx = Node(item)
idx.setNext(current)
idx.setPrev(current.getPrev())
if idx.getPrev() is not None:
idx.getPrev().setNext(idx)
current.setPrev(idx)
self.length += 1
实现idx和search:
def index(self, item):
current, n = self.head, 0
while current is not None:
if current.getData() == item:
break
current = current.getNext()
n += 1
else:
return None
return n
def search(self, item):
return self.index(item) is not None
实现delete,remove,pop:
def delete(self, current): # 删除节点current
if self.head == current:
self.head = current.getNext()
if self.tail == current:
self.tail = current.getPrev()
if current.getPrev() is not None:
current.getPrev().setNext(current.getNext())
if current.getNext() is not None:
current.getNext().setPrev(current.getPrev())
self.length -= 1
def remove(self, item): # 删除元素item
current = self.head
while current is not None:
if current.getData() == item:
self.delete(current)
break
current = current.getNext()
def pop(self, n=None): # pop 功能
if n is None:
n = self.length - 1
current, i = self.head, 0
while i < n:
current = current.getNext()
i += 1
dat = current.getData()
self.delete(current)
return dat
选做:
def __str__(self):
tlst = []
current = self.head
while current is not None:
tlst.append(current.getData())
current = current.getNext()
return str(tlst)
__repr__ = __str__
def __getitem__(self, key):
if isinstance(key, int):
current, i = self.head, 0
while i < key:
current = current.getNext()
i += 1
if current is not None:
return current.getData()
else:
raise StopIteration
elif isinstance(key, slice):
start = 0 if key.start is None else key.start
stop = self.length if key.stop is None else key.stop
step = 1 if key.step is None else key.step # 默认参数
current, i = self.head, 0
while i < start: # 定位到start
current = current.getNext()
i += 1
dcopy = DoublyLinkedList()
while i < stop: # 依次输出
dcopy.append(current.getData())
s = step
while current is not None and s > 0:
current = current.getNext()
s -= 1
i += step
return dcopy
def __eq__(self, other):
if other is None or not isinstance(other, DoublyLinkedList):
return False
if len(self) != len(other):
return False
for s, o in zip(self, other):
if s != o:
return False
else:
return True
结果检验:
输入:
# 检验
print("======== 5-DoublyLinkedList ========")
mylist = DoublyLinkedList()
for i in range(0, 20, 2):
mylist.append(i)
mylist.add(3)
mylist.remove(6)
print(mylist.getTail().getPrev().getData()) # 16
print(mylist.isEmpty()) # False
print(mylist.search(5)) # False
print(mylist.size()) # 10
print(mylist.index(2)) # 2
print(mylist.pop()) # 18
print(mylist.pop(2)) # 2
print(mylist) # [3, 0, 4, 8, 10, 12, 14, 16]
mylist.insert(3, "10")
print(len(mylist)) # 9
print(mylist[4]) # 8
print(mylist[3:8:2]) # ['10', 10, 14]
输出:
======== 5-DoublyLinkedList ========
16
False
False
10
2
18
2
[3, 0, 4, 8, 10, 12, 14, 16]
9
8
['10', 10, 14]
文章内容参考 python数据结构与算法课程 陈斌
本文介绍了几种典型的数据结构算法应用案例,包括中缀表达式求值、基数排序、HTML标记匹配等,并给出了详细的代码实现。
568

被折叠的 条评论
为什么被折叠?



