图有两种最基本的搜索算法,一种是深度优先搜索,另一种是广度优先搜索。本节先介绍深度优先搜索。
深度优先遍历图的方法是,从图中某顶点v出发: 1 访问顶点v; 2 依次从v的未被访问的邻接点出发,对图进行深度优先遍历;直至图中和v有路径相通的顶点都被访问; 3 若此时图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止。
有一个图如下,求深度优先搜索顺序。
分析:首先看看每个元素和哪些元素相邻
元素 | 相邻元素 |
---|---|
1 | 2,3 |
2 | 1,4,5 |
3 | 1,6,7 |
4 | 2,8 |
5 | 2,8 |
6 | 3,7 |
7 | 3,6 |
8 | 4,5 |
(1)假设从节点1开始遍历(事实上可以从任何一个节点开始),与1相邻的是2和3 (2)遍历2之后,进入递归。2有三个相邻元素,1,4,5。因为1已经遍历过了,因此遍历4 (3)遍历4之后,进入递归。与4相邻的是2和8,因为2已经遍历过了,所以遍历8 (4)遍历8之后,进入递归。与8相邻的是4和5,因为4已经遍历过了,所以遍历5 (5)遍历5之后,进入递归。与5相邻的是2和8,因为2和8都已经遍历过了,所以递归终止。返回步骤(4) (6)因为步骤(4)中的4和5都已经遍历过了,返回步骤(3) (7)因为步骤(3)中的2和8都已经遍历过了,返回步骤(2) (8)因为步骤(2)中的1,4,5都已经遍历过了,返回步骤(1) (9)因为步骤(1)中的2已经遍历过了,这次遍历的是3 (10)遍历3之后,进入递归。与3相邻的是6和7,所以遍历6 (11)遍历6之后,进入递归。与6相邻的是3和7,因为3已经遍历过了,所以遍历7 (12)遍历7之后,进入递归。与7相邻的是3和6,因为3和6都已经遍历过了,递归结束。返回步骤(11) (13)在(11)中,3和7都遍历过了,返回步骤(10) (14)在(10)中,6和7都遍历过,返回步骤(1) (15)在步骤(1)中,没有未遍历过的元素。遍历结束。 由上面的15个步骤可知,深度搜索遍历的顺序为:1,2,4,8,5,3,6,7。
class Graph(object):
def __init__(self):
self.node_neighbors = {}
self.visited = {}
def add_nodes(self,nodelist):
for node in nodelist:
self.add_node(node)
def add_node(self,node):
if not node in self.nodes():
self.node_neighbors[node] = []
def add_edge(self,edge):
u,v = edge
if(v not in self.node_neighbors[u] and u != v):
self.node_neighbors[u].append(v)
self.node_neighbors[v].append(u)
def nodes(self):
return self.node_neighbors.keys()
def depth_first_search(self,root=None):
order = []
def dfs(node):
self.visited[node] = True
order.append(node)
for n in self.node_neighbors[node]:
if not n in self.visited:
dfs(n)
if root in self.nodes():
dfs(root)
for node in self.nodes():
if not node in self.visited:
dfs(node)
return order
if __name__ == '__main__':
g = Graph()
g.add_nodes([i+1 for i in range(8)])
g.add_edge((1, 2))
g.add_edge((1, 3))
g.add_edge((2, 4))
g.add_edge((2, 5))
g.add_edge((4, 8))
g.add_edge((5, 8))
g.add_edge((3, 6))
g.add_edge((3, 7))
g.add_edge((6, 7))
print ("Original nodes: ", g.nodes())
order = g.depth_first_search(1)
print ("Depth-First-Search order: ", order)
运行结果:
Original nodes: dict_keys([1, 2, 3, 4, 5, 6, 7, 8])
Depth-First-Search order: [1, 2, 4, 8, 5, 3, 6, 7]