问题描述
我有一个基本的递归深度优先搜索程序,可以搜索大树中未探索的路径。
有没有一种方法可以暂停并保存树,以便以后可以继续搜索而不是每次结束程序都重新启动搜索?
我正在使用python和一个名为pycharm的python IDE。
解决方法
您必须使用DFS的迭代版本,方法是将堆栈对象保留在内置的递归堆栈中。
然后,我们可以侦听Ctrl+C
按钮按下事件,以指示应该暂停DFS。
暂停后,我们可以将dfs状态腌制(序列化)到文件中。
重新启动脚本后,它将检测到该pickle文件的存在并恢复DFS。
import pickle
import os
import multiprocessing
import signal
import time
ctrl_c_pressed_event = multiprocessing.Event()
ctrl_c_pressed_event.clear()
def ctrl_c_handler(*args):
ctrl_c_pressed_event.set()
signal.signal(signal.SIGINT,ctrl_c_handler)
GRAPH_PICKLE_PATH = 'graph_pickle.pkl'
class DfsState:
def __init__(self,visited=set(),path=[],dfs_q=[]):
self.visited = visited
self.path = path
self.dfs_q = dfs_q
def __str__(self):
return 'visited={}\npath={}\nq={}'.format(self.visited,self.path,self.dfs_q)
class Graph:
def __init__(self):
# Graph is stored in a dictionary of <vertex> vs <set of vertices>
# Each vertex is just an int
self.neighbours = {}
self.vertices = set()
self.dfs_state = DfsState()
def add_edge(self,src,dst):
"""
Add an edge from `src` to `dst`.
"""
self.vertices.add(src)
self.vertices.add(dst)
src_neighbours = self.neighbours.get(src,set())
src_neighbours.add(dst)
self.neighbours[src] = src_neighbours
def get_all_edges(self):
return self.neighbours
def get_neighbours(self,src):
return self.neighbours.get(src,set())
def add_vertex(self,src):
if src not in self.neighbours:
self.neighbours[src] = set()
self.vertices.add(src)
def dfs_iterative(graph):
visited = graph.dfs_state.visited
path = graph.dfs_state.path
dfs_q = graph.dfs_state.dfs_q
while dfs_q:
if ctrl_c_pressed_event.is_set():
return 'PAUSED'
current = dfs_q.pop()
print(current)
if current not in visited:
visited.add(current)
path.append(current)
neighbours = graph.get_neighbours(current)
for neighbour in neighbours:
if neighbour not in visited:
dfs_q.append(neighbour)
# Just for testing
time.sleep(1)
return 'DONE'
def init_graph():
graph = Graph()
graph.add_edge(1,2)
graph.add_edge(1,3)
graph.add_edge(2,5)
graph.add_edge(3,2)
graph.add_edge(3,4)
graph.add_edge(4,5)
graph.add_edge(5,6)
graph.add_edge(5,7)
graph.add_edge(7,8)
start_vertex = 1
graph.dfs_state.dfs_q = [start_vertex]
return graph
def pickle_graph(graph):
pickle.dump(graph,open(GRAPH_PICKLE_PATH,'wb'))
def load_pickle_graph():
return pickle.load(open(GRAPH_PICKLE_PATH,"rb" ))
def main():
if os.path.exists(GRAPH_PICKLE_PATH):
graph = load_pickle_graph()
print('Resuming DFS')
print(graph.dfs_state)
else:
graph = init_graph()
status = dfs_iterative(graph)
pickle_graph(graph)
print('\n' + str(graph.dfs_state))
if status == 'PAUSED':
print('DFS paused!')
else:
print('DFS complete!')
if __name__ == "__main__":
main()
输出:
>>> ajaggi-mn1:~/Documents/personal/practice/python$ python a.py
1
3
4
^C
visited=set([1,3,4])
path=[1,4]
q=[2,2,5]
DFS paused!
>>> ajaggi-mn1:~/Documents/personal/practice/python$ python a.py
Resuming DFS
visited=set([1,5]
5
7
8
^C
visited=set([1,4,5,7,8])
path=[1,8]
q=[2,6]
DFS paused!
>>> ajaggi-mn1:~/Documents/personal/practice/python$ python a.py
Resuming DFS
visited=set([1,6]
6
2
2
visited=set([1,6,8,2]
q=[]
DFS complete!
>>> ajaggi-mn1:~/Documents/personal/practice/python$ python a.py
Resuming DFS
visited=set([1,2]
q=[]
visited=set([1,2]
q=[]
DFS complete!