广度优先搜索和深度优先搜索
上篇已经讲了广度优先与深度优先搜索,这边就写了,虽然说还可以有一些扩展,比如说算法导论里面说的什么 深度,广度优先搜索树, 它们的一些特点什么的, 反正我基本上没用到过,我也说不清。
树的三种遍历的实现
我想跟网上大部分写的不同一点,然后自己用数组模拟的二叉树(网上大部分都是模拟的指针)
代码:(重点在非递归。。都说所有的递归可以转成非递归,感觉好难转啊,不知道有没有什么套路)
class Tree:
def __init__(self, lines = [0], ll = 1):
self.lines = lines
self.ll = ll
def add(self, data):
self.lines.append(data)
self.ll += 1
def front_dfs(self, k = 1):
if (k >= self.ll):
return ()
state = (self.lines[k],) + self.front_dfs(k<<1) + self.front_dfs(k<<1|1)
return state
def middle_dfs(self, k = 1):
if (k >= self.ll):
return ()
state = self.middle_dfs(k<<1) + (self.lines[k],) + self.middle_dfs(k<<1|1)
return state
def later_dfs(self, k = 1):
if (k >= self.ll):
return ()
state = self.later_dfs(k<<1) + self.later_dfs(k<<1|1) + (self.lines[k],)
return state
#普通的用栈模拟递归 注意后进先出
def front_stack1(self, k = 1):
myStack = []
myStack.append(k)
state = ()
while myStack:
k = myStack.pop()
state += (self.lines[k],)
if k<<1|1 < self.ll: #右子树先进
myStack.append(k<<1|1)
if k<<1 < self.ll: #左子树再进
myStack.append(k<<1)
k = k<<1|1
return state
#第二种就是下面写的中序遍历改一下输出位置
def front_stack2(self, k = 1):
myStack = []
state = ()
while k < self.ll or myStack:
while k < self.ll:
state += (self.lines[k],) #这里
myStack.append(k)
k <<= 1
k = myStack.pop()
k = k<<1|1
return state
#中序遍历相当于。。。我反正说不清,反正就是可以
def middle_stack(self, k = 1):
myStack = []
state = ()
while k < self.ll or myStack:
while k < self.ll:
myStack.append(k)
k <<= 1
k = myStack.pop()
state += (self.lines[k],) #这里
k = k<<1|1
return state
def later_stack1(self, k = 1):
myState = []
state = ()
#pCur:当前访问节点,pLastVisit:上次访问节点
pLastVisit = 0
pCur = k
#先把pCur移动到左子树最下边
while pCur < self.ll:
myState.append(pCur)
pCur <<= 1
while (len(myState) != 0):
pCur = myState.pop()
#一个根节点被访问的前提是:无右子树或右子树已被访问过
if pCur<<1|1 >= self.ll or pCur<<1|1 == pLastVisit:
state += (self.lines[pCur],)
pLastVisit = pCur
else:
#根节点再次入栈
myState.append(pCur)
pCur = pCur<<1|1
#进入右子树,且可肯定右子树一定不为空
while pCur < self.ll:
myState.append(pCur)
pCur <<= 1
return state
#后序遍历可以看成 先遍历根结点再右子树然后再左子树的 逆序
def later_stack2(self, k = 1):
state = ()
myState = [1]
while myState:
k = myState.pop()
state = (self.lines[k],) + state #逆序
if k<<1 < self.ll:
myState.append(k<<1)
if k<<1|1 < self.ll:
myState.append(k<<1|1)
return state
x = Tree()
for i in range(10):
x.add(i)
print(x.later_stack1())
print(x.later_stack2())
网上大神是模拟的用指针来表示二叉树的写法:(比较容易看懂)
class Node(object):
"""节点类"""
def __init__(self, elem=-1, lchild=None, rchild=None):
self.elem = elem
self.lchild = lchild
self.rchild = rchild
class Tree(object):
"""树类"""
def __init__(self):
self.root = Node()
self.myQueue = []
def add(self, elem):
"""为树添加节点"""
node = Node(elem)
if self.root.elem == -1: # 如果树是空的,则对根节点赋值
self.root = node
self.myQueue.append(self.root)
else:
treeNode = self.myQueue[0] # 此结点的子树还没有齐。
if treeNode.lchild == None:
treeNode.lchild = node
self.myQueue.append(treeNode.lchild)
else:
treeNode.rchild = node
self.myQueue.append(treeNode.rchild)
self.myQueue.pop(0) # 如果该结点存在右子树,将此结点丢弃。
def front_digui(self, root):
"""利用递归实现树的先序遍历"""
if root == None:
return
print (root.elem,)
self.front_digui(root.lchild)
self.front_digui(root.rchild)
def middle_digui(self, root):
"""利用递归实现树的中序遍历"""
if root == None:
return
self.middle_digui(root.lchild)
print (root.elem,)
self.middle_digui(root.rchild)
def later_digui(self, root):
"""利用递归实现树的后序遍历"""
if root == None:
return
self.later_digui(root.lchild)
self.later_digui(root.rchild)
print (root.elem,)
def front_stack(self, root):
"""利用堆栈实现树的先序遍历"""
if root == None:
return
myStack = []
node = root
while node or myStack:
while node: #从根节点开始,一直找它的左子树
print (node.elem,)
myStack.append(node)
node = node.lchild
node = myStack.pop() #while结束表示当前节点node为空,即前一个节点没有左子树了
node = node.rchild #开始查看它的右子树
def middle_stack(self, root):
"""利用堆栈实现树的中序遍历"""
if root == None:
return
myStack = []
node = root
while node or myStack:
while node: #从根节点开始,一直找它的左子树
myStack.append(node)
node = node.lchild
node = myStack.pop() #while结束表示当前节点node为空,即前一个节点没有左子树了
print (node.elem,)
node = node.rchild #开始查看它的右子树
def later_stack(self, root):
"""利用堆栈实现树的后序遍历"""
if root == None:
return
myStack1 = []
myStack2 = []
node = root
myStack1.append(node)
while myStack1: #这个while循环的功能是找出后序遍历的逆序,存在myStack2里面
node = myStack1.pop()
if node.lchild:
myStack1.append(node.lchild)
if node.rchild:
myStack1.append(node.rchild)
myStack2.append(node)
while myStack2: #将myStack2中的元素出栈,即为后序遍历次序
print (myStack2.pop().elem,)
def level_queue(self, root):
"""利用队列实现树的层次遍历"""
if root == None:
return
myQueue = []
node = root
myQueue.append(node)
while myQueue:
node = myQueue.pop(0)
print (node.elem,)
if node.lchild != None:
myQueue.append(node.lchild)
if node.rchild != None:
myQueue.append(node.rchild)
if __name__ == '__main__':
"""主函数"""
elems = range(10) #生成十个数据作为树节点
tree = Tree() #新建一个树对象
for elem in elems:
tree.add(elem) #逐个添加树的节点
print ('队列实现层次遍历:')
tree.level_queue(tree.root)
print ('\n\n递归实现先序遍历:')
tree.front_digui(tree.root)
print ('\n递归实现中序遍历:' )
tree.middle_digui(tree.root)
print ('\n递归实现后序遍历:')
tree.later_digui(tree.root)
print ('\n\n堆栈实现先序遍历:')
tree.front_stack(tree.root)
print ('\n堆栈实现中序遍历:')
tree.middle_stack(tree.root)
print ('\n堆栈实现后序遍历:')
tree.later_stack(tree.root)
最小生成树实现
1. Prim算法
大概就是 假设边集u 是图G(V,E)中某个最小生成树的子集, 然后使用贪心策略选一条安全边加入, 直到选了 V-1条
跟单源最短路径里面的dijkstal算法很像
还记得上篇里的那5行代码吗:orz
代码:(复杂度为O(ElgV),如果使用斐波那契堆来实现优先队列Q的话会变成 O(E+Vlg(V)) )
from heapq import heappop, heappush
#G是用字典描述的邻接链表
def prim(G, s):
P, Q = {}, [(0, None, s)]
while Q:
_, p, u = heappop(Q)#优先队列每次取短的那一条边
if u in P: continue
P[u] = p #标记u节点,并记录u的前驱结点
#松弛操作
for v, w in G[u].items():
heappush(Q, (w, u, v))
return P
2.kruskal算法(实质也是贪心算法)
在图G(V,E)中先假设每个点都是独立的,也就是它们各自形成一棵树,一共有V颗。
再按非递减的方式遍历所有的边,如果当前这条边属于两个不同的集合则,将这条边加入最小生成树,并将这两个集合合并。
代码:(复杂度O(ElgV))
#kruskal算法, 主要是并查集的应用
def find(C, u):
if C[u] != u:
C[u] = find(C, C[u])
return C[u]
def union(C, R, u, v):
u, v = find(C, u), find(C, v)
if R[u] > R[v]:
C[v] = u
else:
C[u] = v
if R[u] == R[v]:
R[v] += 1
def kruskal(G):
E = [(G[u][v], u, v) for u in G for v in G[u]]
T = set()
C, R = {u: u for u in G}, {u: 0 for u in G}
for _, u, v in sorted(E):
if find(C, u) != find(C, v):
T.add((u, v))
union(C, R, u, v)
return T