暂停递归深度优先搜索
Pausing a recursive depth-first search
我有一个基本的递归深度优先搜索程序,可以在大树中搜索未探索的路径。
有没有一种方法可以暂停并保存树,这样我就可以稍后继续搜索,而不是每次结束程序时都重新开始搜索?
我正在使用 python 和一个名为 pycharm.
的 python IDE
您将不得不使用 DFS 的迭代版本,方法是将堆栈对象保留在内置递归堆栈的位置。
然后我们可以收听 Ctrl+C
按钮按下事件,以发出 DFS 应该暂停的信号。
当它暂停时,我们可以将 dfs 状态 pickle(序列化)到文件中。
当脚本重新启动时,它将检测到此 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, 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, 3, 4]
q=[2, 2, 5]
DFS paused!
>>> ajaggi-mn1:~/Documents/personal/practice/python$ python a.py
Resuming DFS
visited=set([1, 3, 4])
path=[1, 3, 4]
q=[2, 2, 5]
5
7
8
^C
visited=set([1, 3, 4, 5, 7, 8])
path=[1, 3, 4, 5, 7, 8]
q=[2, 2, 6]
DFS paused!
>>> ajaggi-mn1:~/Documents/personal/practice/python$ python a.py
Resuming DFS
visited=set([1, 3, 4, 5, 7, 8])
path=[1, 3, 4, 5, 7, 8]
q=[2, 2, 6]
6
2
2
visited=set([1, 2, 3, 4, 5, 6, 7, 8])
path=[1, 3, 4, 5, 7, 8, 6, 2]
q=[]
DFS complete!
>>> ajaggi-mn1:~/Documents/personal/practice/python$ python a.py
Resuming DFS
visited=set([1, 2, 3, 4, 5, 6, 7, 8])
path=[1, 3, 4, 5, 7, 8, 6, 2]
q=[]
visited=set([1, 2, 3, 4, 5, 6, 7, 8])
path=[1, 3, 4, 5, 7, 8, 6, 2]
q=[]
DFS complete!
我有一个基本的递归深度优先搜索程序,可以在大树中搜索未探索的路径。
有没有一种方法可以暂停并保存树,这样我就可以稍后继续搜索,而不是每次结束程序时都重新开始搜索?
我正在使用 python 和一个名为 pycharm.
您将不得不使用 DFS 的迭代版本,方法是将堆栈对象保留在内置递归堆栈的位置。
然后我们可以收听 Ctrl+C
按钮按下事件,以发出 DFS 应该暂停的信号。
当它暂停时,我们可以将 dfs 状态 pickle(序列化)到文件中。
当脚本重新启动时,它将检测到此 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, 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, 3, 4]
q=[2, 2, 5]
DFS paused!
>>> ajaggi-mn1:~/Documents/personal/practice/python$ python a.py
Resuming DFS
visited=set([1, 3, 4])
path=[1, 3, 4]
q=[2, 2, 5]
5
7
8
^C
visited=set([1, 3, 4, 5, 7, 8])
path=[1, 3, 4, 5, 7, 8]
q=[2, 2, 6]
DFS paused!
>>> ajaggi-mn1:~/Documents/personal/practice/python$ python a.py
Resuming DFS
visited=set([1, 3, 4, 5, 7, 8])
path=[1, 3, 4, 5, 7, 8]
q=[2, 2, 6]
6
2
2
visited=set([1, 2, 3, 4, 5, 6, 7, 8])
path=[1, 3, 4, 5, 7, 8, 6, 2]
q=[]
DFS complete!
>>> ajaggi-mn1:~/Documents/personal/practice/python$ python a.py
Resuming DFS
visited=set([1, 2, 3, 4, 5, 6, 7, 8])
path=[1, 3, 4, 5, 7, 8, 6, 2]
q=[]
visited=set([1, 2, 3, 4, 5, 6, 7, 8])
path=[1, 3, 4, 5, 7, 8, 6, 2]
q=[]
DFS complete!