目录
1. 二叉树的 list 实现和表达式树
""" Implementing binary trees as embedded list
"""
def BiTree(data, left, right):
return [data, left, right]
def is_empty_BiTree(bitree):
return bitree == []
def root(bitree):
return bitree[0]
def leftch(bitree):
return bitree[1]
def rightch(bitree):
return bitree[2]
def set_root(bitree, data):
bitree[0] = data
def set_leftch(bitree, left):
bitree[1] = left
def set_rightch(bitree, right):
bitree[2] = right
###############################################
#### Functions for ############################
#### building and manipulating ################
#### mathematical expressions ################
from numbers import Number
def make_sum(a, b):
return ['+', a, b]
def make_prod(a, b):
return ['*', a, b]
def make_diff(a, b):
return ['-', a, b]
def make_div(a, b):
return ['/', a, b]
def is_basic_exp(a):
return not isinstance(a, list)
def is_compose_exp(a):
return isinstance(a, list)
def eval_exp(e):
if is_basic_exp(e):
return e
op, a, b = e[0], eval_exp(e[1]), eval_exp(e[2])
if op == '+':
return eval_sum(a, b)
elif op == '-':
return eval_diff(a, b)
elif op == '*':
return eval_prod(a, b)
elif op == '/':
return eval_div(a, b)
else:
raise ValueError("Unknown operator:", op)
def eval_sum(a, b):
if isinstance(a, Number) and isinstance(b, Number):
return a + b
if isinstance(a, Number) and a == 0:
return b
if isinstance(b, Number) and b == 0:
return a
return make_sum(a, b)
def eval_diff(a, b):
if isinstance(a, Number) and isinstance(b, Number):
return a - b
if isinstance(a, Number) and a == 0:
return -b
if isinstance(b, Number) and b == 0:
return a
return make_diff(a, b)
def eval_prod(a, b):
if isinstance(a, Number) and isinstance(b, Number):
return a * b
if (isinstance(a, Number) and a == 0 or
isinstance(b, Number) and b == 0):
return 0
if isinstance(a, Number) and a == 1:
return b
if isinstance(b, Number) and b == 1:
return a
return make_prod(a, b)
def eval_div(a, b):
if isinstance(a, Number) and isinstance(b, Number):
return a / b
if isinstance(a, Number) and a == 0:
return 0
if isinstance(b, Number) and b == 0:
raise ZeroDivisionError
if isinstance(b, Number) and b == 1:
return a
return make_div(a, b)
if __name__ == '__main__':
## t1 = BiTree(2, BiTree(4, [], []), BiTree(8, [], []))
## print(t1)
## set_leftch(leftch(t1), BiTree(5, [], []))
## print(t1)
e1 = make_prod(make_sum(2, 3), make_diff(4, 5))
e2 = make_prod(make_diff(make_prod(2, 'a'), 3), make_diff(4, 5))
e3 = make_div(make_sum(make_prod(2, 7), make_div(0, 'b')), make_div('a', 1))
# eval_exp(['$', 2, 3]) # This will cause an exception because $ is not a valid operator
2. 优先队列的两种实现
# This file contains two
# implementations of priority queues:
# 1, as sorted list
# 2, as heap stored in a list
# and in addition,
# an implementation of heap sort function
class PrioQueueError(ValueError):
pass
class PrioQue:
""" Implementing binary trees as sorted list
"""
def __init__(self, elist = []):
self.elems = list(elist)
self.elems.sort()
def is_empty(self):
return self.elems == []
def peek(self):
if self.is_empty():
raise PrioQueueError("in top")
return self.elems[len(self.elems)-1]
def dequeue(self):
if self.is_empty():
raise PrioQueueError("in pop")
return self.elems.pop()
def enqueue(self, e):
i = len(self.elems) - 1
while i >= 0:
if self.elems[i] <= e:
i -= 1
else: break
self.elems.insert(i+1, e)
class PrioQueue:
""" Implementing binary trees as heaps
"""
def __init__(self, elist = []):
self.elems = list(elist)
if elist != []:
self.buildheap()
def is_empty(self):
return self.elems == []
def peek(self):
if self.is_empty():
raise PrioQueueError("in top")
return self.elems[0]
def enqueue(self, e):
self.elems.append(None) # add a dummy element
self.siftup(e, len(self.elems)-1)
def siftup(self, e, last):
elems, i, j = self.elems, last, (last-1)//2
while i > 0 and e < elems[j]:
elems[i] = elems[j]
i, j = j, (j-1)//2
elems[i] = e
def dequeue(self):
if self.is_empty():
raise PrioQueueError("in pop")
elems = self.elems
e0 = elems[0]
e = elems.pop()
if len(elems) > 0:
self.siftdown(e, 0, len(elems))
return e0
def siftdown(self, e, begin, end):
elems, i, j = self.elems, begin, begin*2+1
while j < end: # invariant: j == 2*i+1
if j+1 < end and elems[j+1] < elems[j]:
j += 1 # elems[j] <= its brother
if e < elems[j]: # e is the smallest of the three
break
elems[i] = elems[j] # elems[j] is the smallest, move it up
i, j = j, 2*j+1
elems[i] = e
def buildheap(self):
end = len(self.elems)
for i in range(end//2, -1, -1):
self.siftdown(self.elems[i], i, end)
def heap_sort(elems):
def siftdown(elems, e, begin, end):
i, j = begin, begin*2+1
while j < end: # invariant: j == 2*i+1
if j+1 < end and elems[j+1] < elems[j]:
j += 1 # elems[j] <= its brother
if e < elems[j]: # e is the smallest of the three
break
elems[i] = elems[j] # elems[j] is the smallest, move it up
i, j = j, 2*j+1
elems[i] = e
end = len(elems)
for i in range(end//2, -1, -1):
siftdown(elems, elems[i], i, end)
for i in range((end-1), 0, -1):
e = elems[i]
elems[i] = elems[0]
siftdown(elems, e, 0, i)
from random import randint, random
def test1():
print("Test class PrioQue:")
pq = PrioQue()
for i in range(12):
pq.enqueue(randint(0, 30))
while not pq.is_empty():
print(pq.dequeue())
def test2():
print("Test class PrioQueue:")
pq = PrioQueue()
for i in range(12):
pq.enqueue(randint(0, 30))
while not pq.is_empty():
print(pq.dequeue())
def test3():
print("Test function heap_sort:")
lst = [randint(1, 30) for i in range(15)]
print(lst)
heap_sort(lst)
print(lst)
if __name__ == '__main__':
test1()
test2()
test3()
pass
3. 海关检查站模拟
""" Implementing binary trees as embedded list
"""
from random import randint, random
from PrioQueue import PrioQueue, PrioQueueError
from SQueue import SQueue, QueueUnderflow
car_arrive_interval = (1, 2)
car_check_time = (3, 5)
class Simulation:
def __init__(self, duration):
self._eventq = PrioQueue()
self._time = 0
self._duration = duration
def run(self):
while not self._eventq.is_empty():
event = self._eventq.dequeue()
self._time = event.time()
if self._time > self._duration:
break
event.run() # may cause new event(s)
def add_event(self, event): self._eventq.enqueue(event)
def cur_time(self): return self._time
class Customs:
def __init__(self, gate_num, duration):
self.simulation = Simulation(duration)
self.waitline = SQueue()
self.duration = duration
self.gates = [0]*gate_num
self.total_wait_time = 0
self.total_used_time = 0
self.car_num = 0
def wait_time_acc(self, n): self.total_wait_time += n
def total_time_acc(self, n): self.total_used_time += n
def car_count_1(self): self.car_num += 1
def add_event(self, event): self.simulation.add_event(event)
def cur_time(self): return self.simulation.cur_time()
def enqueue(self, car): self.waitline.enqueue(car)
def has_queued_car(self): return not self.waitline.is_empty()
def next_car(self) : return self.waitline.dequeue()
def find_gate(self):
for i in range(len(self.gates)):
if self.gates[i] == 0:
self.gates[i] = 1
return i
return None
def free_gate(self, i):
if self.gates[i] == 1:
self.gates[i] = 0
else:
raise ValueError("Clear gate error.")
def simulate(self):
Arrive(0, self) # initially generate one car
self.simulation.run()
self.statistics()
def statistics(self):
print("Simulate " + str(self.duration) + " minutes, for "
+ str(len(self.gates)) + " gates")
print(self.car_num, "cars pass the customs")
print("Avarage waiting time:",
self.total_wait_time/self.car_num)
print("Avarage passing time:",
self.total_used_time/self.car_num)
i = 0
while not self.waitline.is_empty():
self.waitline.dequeue()
i += 1
print(i, "cars are in waiting line.")
class Car:
def __init__(self, arrive_time):
self.time = arrive_time
def arrive_time(self):
return self.time
def event_log(time, name): pass
# print("Event: " + name + ", happens at " + str(time))
class Event:
def __init__(self, event_time, customs):
self.ctime = event_time
self.customs = customs
def __lt__(self, other_event):
return self.ctime < other_event.ctime
def __le__(self, other_event):
return self.ctime <= other_event.ctime
def time(self): return self.ctime
def run(self, time, event_name): pass
# a run of coming event will enter the next coming event and
# maybe a check and leave event
class Arrive(Event):
def __init__(self, arrive_time, customs):
Event.__init__(self, arrive_time, customs)
self.customs.add_event(self)
def run(self):
time, customs = self.ctime, self.customs
event_log(time, "car arrive")
# We genarate the next Arrive event
Arrive(time + randint(*car_arrive_interval), customs)
# dealing with current Arrive car
car = Car(time)
i = customs.find_gate()
if i is not None:
event_log(time, "car check")
Leave(time + randint(*car_check_time), i, car, customs)
else:
customs.enqueue(car)
# a run of leaving event will cause some calculations
class Leave(Event):
def __init__(self, leave_time, gate_num, car, customs):
Event.__init__(self, leave_time, customs)
self.car = car
self.gate_num = gate_num
self.customs.add_event(self)
def run(self):
time, customs = self.ctime, self.customs
event_log(time, "car leave")
customs.free_gate(self.gate_num)
customs.car_count_1()
customs.total_time_acc(time - self.car.arrive_time())
if customs.has_queued_car():
car = customs.next_car()
i = customs.find_gate()
event_log(time, "car check")
customs.wait_time_acc(time - car.arrive_time())
Leave(time + randint(*car_check_time), i, car, customs)
if __name__ == '__main__':
cus = Customs(2, 480)
cus.simulate()
pass
4. 二叉树遍历和二叉树类
""" classes and functions for binary trees
"""
class BiTNodeError(ValueError):
pass
class BiTNode:
def __init__(self, dat, left, right):
self.data = dat
self.left = left
self.right = right
def count_BiTNodes(t):
if t is None:
return 0
else:
return 1 + count_BiTNodes(t.left) + count_BiTNode(t.right)
def sum_BiTNodes(t):
if t is None:
return 0
else:
return t.dat + sum_BiTNodes(t.left) + sum_BiTNodes(t.right)
def preorder(t, proc):
if t is None: return
assert(isinstence(t, BiTNode))
proc(t.data)
preorder(t.left)
preorder(t.right)
def inorder(t, proc):
if t is None: return
inorder(t.left)
proc(t.data)
inorder(t.right)
def postorder(t, proc):
if t is None: return
postorder(t.left)
postorder(t.right)
proc(t.data)
from SQueue import *
def levelorder(t, proc):
q = SQueue()
q.enqueue(t)
while not q.is_empty():
n = q.dequeue()
if t is None: continue
q.enqueue(t.left)
q.enqueue(t.right)
proc(t.data)
from SStack import *
def preorder_nonrec(t, proc):
s = SStack()
while t is not None or not s.is_empty():
while t is not None: # go down along left chain
s.push(t.right) # push right branch into stack
proc(t.data)
t = t.left
t = s.pop() # left chain ends, backtrack
def preorder_iter(t):
s = SStack()
while t is not None or not s.is_empty():
while t is not None:
s.push(t.right)
yield t.data
t = t.left
t = s.pop()
def inorder_nonrec(t, proc):
s = SStack()
while t is not None or not s.is_empty():
while t is not None:
s.push(t)
t = t.left
t = s.pop()
proc(t.data)
t = t.right
def postorder_nonrec(t, proc):
s = SStack()
while t is not None or not s.is_empty():
while t is not None: # iterate until top has no child
s.push(t)
t = t.left if t.left is not None else t.right
# if we can go left, go, otherwise, go right
t = s.pop() # get the node to be access
proc(t.data)
if not s.is_empty() and s.top().left == t:
t = s.top().right # end of left visit, turn right
else:
t = None # end of right visit, force to backtrack
def print_BiTNodes(t):
if t is None:
print("^", end="")
return
print("(" + str(t.data), end="")
print_BiTNodes(t.left)
print_BiTNodes(t.right)
print(")", end="")
class BiTree:
def __init__(self):
self._root = None
def is_empty(self):
return self._root == None
def set_root(self, rootnode):
self._root = rootnode
def set_left(self, leftchild):
self._root.left = leftchild
def set_right(self, rightchild):
self._root.right = rightchild
def root(self): return self._root
def leftchild(self): return self._root.left
def rightchild(self): return self._root.right
def preorder_iter(self):
t, s = self._root, SStack()
while t is not None or not s.is_empty():
while t is not None:
s.push(t.right)
yield t.data
t = t.left
t = s.pop()
if __name__ == '__main__':
pass
5. 哈夫曼算法
""" classes and functions for binary trees
"""
from PrioQueue import PrioQueue, PrioQueueError
from BiTree1 import BiTNode, print_BiTNodes
class HTNode(BiTNode):
def __lt__(self, othernode):
return self.data < othernode.data
class HuffmanPrioQ(PrioQueue):
def number(self): return self.num
def HuffmanTree(weights):
trees = HuffmanPrioQ()
for w in weights:
trees.enqueue(HTNode(w, None, None))
while trees.number() > 1:
t1 = trees.dequeue()
t2 = trees.dequeue()
x = t1.data + t2.data
trees.enqueue(HTNode(x, t1, t2))
return trees.dequeue()
if __name__ == '__main__':
## t = BiTNode(1, BiTNode(2, None, None), BiTNode(3, None, None))
## print_BiTNodes(t)
## print("\n")
h = HuffmanTree([2, 3, 7, 10, 4, 2, 5])
print_BiTNodes(h)
pass