(7)函数breadth_first_search实现了广度优先搜索算法。它使用一个队列来存储待探索的节点,并通过迭代地从队列中取出节点来搜索路径。在搜索过程中,它会调用`add_neighbours`函数来添加节点的相邻节点,并在添加节点后继续搜索。当找到目标节点时,函数会停止搜索,并调用`paint`函数来绘制路径。最后,函数返回搜索得到的路径的距离、步数、队列的最大大小、弹出的节点数以及搜索所用的时间。
def breadth_first_search(start_time):
queue = []
found = False
rear = 0
front = 0
(x, y) = gui.selected_cities[0]
(end_x, end_y) = gui.selected_cities[1]
point = Point(x, y)
end = Point(end_x, end_y)
start = point
# print("Start {}, {}. End {}, {}".format(start.x, start.y, end.x, end.y))
point.index = find_in_ovals(x, y)
queue.append(point) # source
visited = np.zeros(gui.city_count)
visited[point.index] = 1
popped = 0
max_element = 0
while len(queue) > 0 and not found:
point = queue[front]
# print("Çekilen nokta: ", point.x, point.y)
rear -= 1
if point.equal(end):
found = True
print("Path found")
else:
top = add_neighbours(point, queue, rear, visited, end, 2)
if len(queue) > max_element:
max_element = len(queue)
# print("Stack boyutu:", len(queue))
popped += 1
front += 1
if found:
total_distance, step_size = paint(point, start, max_element, popped)
return total_distance, step_size, max_element, popped, time.time() - start_time
else:
message = "Path is not exist."
gui.step_label.config(text=message)
return 0, 0, 0, 0, time.time() - start_time
(8)函数paint用于绘制搜索得到的路径,其参数包括起始节点 `start`、搜索得到的目标节点 `point`、队列或栈的最大大小 `max_element` 以及弹出的节点数 `pops`。函数首先通过回溯得到路径上的所有节点,并计算路径的总距离和步数。然后,它在画布上绘制路径,并更新界面以显示搜索结果的动态过程。绘制路径时,函数会根据搜索速度设置的不同调整绘制的延迟时间。最后,函数返回路径的总距离和步数。
def paint(point, start, max_element, pops):
path = []
step_size = 0
total_distance = 0
delay = 0.3
if gui.speed.get() == 0: # fast
delay = 0.2
elif gui.speed.get() == 1:
delay = 0.5
while not point.equal(start):
path.append(point)
total_distance += distance(point.x, point.y, point.parent.x, point.parent.y, 1)
point = point.parent
step_size += 1
message = "Step Size: {}, Distance: {}".format(step_size, int(total_distance))
message2 = "Maximum Stack Size: {}\nNumber of Pops: {}".format(max_element, pops)
gui.step_label.config(text=message)
gui.output_label.config(text=message2)
for i in range(len(path) - 1, -1, -1):
gui.canvas.create_line(path[i].x + 5, path[i].y + 5, path[i].parent.x + 5, path[i].parent.y + 5,
width=3, fill="yellow")
gui.window.update()
time.sleep(delay)
return total_distance, step_size
(9)下面这段代码定义了run函数,用于执行路径搜索算法并返回搜索结果。首先,它检查连接数、城市数以及连接数阈值是否符合要求,如果不符合则显示相应的错误消息。然后,根据用户选择的算法类型执行对应的搜索函数,并记录搜索过程中的路径距离、步数、最大堆栈/队列大小、弹出节点数以及总运行时间。最后,函数返回这些结果。
def run():
if gui.conn_count < gui.city_total.get() - 1:
msg.showerror(title="Connection Count Error", message="The number of connections is {} it's less than threshold"
" {}.".format(gui.conn_count, gui.city_total.get() - 1))
return
elif gui.city_count + 1 < gui.city_total.get():
msg.showerror(title="City Count Error", message="The number of cities is {} but it's supposed to be {}.".
format(gui.city_count, gui.city_total.get()))
return
elif gui.conn_count < gui.entry.get() - 1:
msg.showinfo(title="Connection Count Info", message="The number connections is {} but it's supposed to be {}."
.format(gui.conn_count, gui.entry.get()))
start = time.time()
if gui.algorithm.get() == 0: # a *
total_distance, step_size, max_element, popped, total_time = a_star_and_best_first_search(0, start)
elif gui.algorithm.get() == 1: # best first search
total_distance, step_size, max_element, popped, total_time = a_star_and_best_first_search(1, start)
elif gui.algorithm.get() == 2:
total_distance, step_size, max_element, popped, total_time = depth_first_search(start)
elif gui.algorithm.get() == 3:
total_distance, step_size, max_element, popped, total_time = breadth_first_search(start)
else:
msg.showerror(title="Algorithm Selection Error", message="You did not choose the algorithm.")
return total_distance, step_size, max_element, popped, total_time
(10)定义函数select_indices,用于随机选择两个城市索引,并确保它们不是邻居关系。它首先随机选择一个城市索引 `index1`,然后找到与该城市相连的城市,并将它们添加到 `neighbours` 列表中。接着,它再次随机选择另一个城市索引 `index2`,直到满足以下两个条件之一:`index1` 不等于 `index2`,或者 `(x1, y1)` 不在 `neighbours` 中。最后,它将所选的城市坐标添加到 `gui.selected_cities` 列表中。
def select_indices():
index1 = random.randint(0, gui.city_total.get() - 1)
index2 = index1
neighbours = []
i = 0
x, y = gui.ovals[index1]["coords"]
while i < len(gui.lines): # find neighbours
x1, y1, x2, y2 = gui.lines[i]["coords"]
if distance(x, y, x1 - 5, y1 - 5, 0) == 0:
neighbours.append((x2 - 5, y2 - 5))
elif distance(x, y, x2 - 5, y2 - 5, 0) == 0:
neighbours.append((x1 - 5, y1 - 5))
i += 1
index2 = random.randint(0, gui.city_total.get() - 1)
x1, y1 = gui.ovals[index2]["coords"]
while index1 == index2 or (x1, y1) in neighbours: # işimizi şansa bırakmıyoruz
index2 = random.randint(0, gui.city_total.get() - 1)
x1, y1 = gui.ovals[index2]["coords"]
print("Selected: ", x, y, x1, y1)
gui.selected_cities.append((x, y))
gui.selected_cities.append((x1, y1))
(11)定义函数test,用于运行一系列测试并将结果写入到 CSV 文件中。在测试过程中,它首先设置城市总数和连接数,并创建一个 CSV 文件以存储测试结果。然后,它循环执行以下步骤:
- 生成随机城市布局。
- 随机选择两个城市作为起点和终点。
- 分别以欧几里德距离和曼哈顿距离作为启发式函数运行 A* 算法。
- 分别以欧几里德距离和曼哈顿距离作为启发式函数运行 BFS 算法。
- 运行深度优先搜索(DFS)算法。
- 运行广度优先搜索(BFS)算法。
在每次运行算法后,将结果写入 CSV 文件中。最后,将这个过程重复执行一百次,以进行大规模测试。
def test():
gui.city_total.set(20)
gui.entry.set(40)
with open('test_outputs.csv', 'w', newline='') as file:
fieldnames = ['algorithm', 'distance', "step size", "max element", "popped", "time"]
writer = csv.DictWriter(file, fieldnames=fieldnames)
writer.writeheader()
for i in range(100):
print("Adım:", i)
gui.create_randomly()
gui.selected_cities = []
select_indices()
accepted = 0
for j in range(6):
if j == 0:
gui.algorithm.set(0)
gui.evaluation.set(0)
total_distance, step_size, max_element, popped, total_time = run()
accepted = total_distance
writer.writerow({"algorithm": "A* with Euclidean", "distance": accepted / total_distance , "step size": step_size,
"max element": max_element, "popped": popped, "time": total_time})
elif j == 1:
gui.algorithm.set(0)
gui.evaluation.set(1)
total_distance, step_size, max_element, popped, total_time = run()
writer.writerow({"algorithm": "A* with Manhattan", "distance": accepted / total_distance , "step size": step_size,
"max element": max_element, "popped": popped, "time": total_time})
elif j == 2:
gui.algorithm.set(1)
gui.evaluation.set(0)
total_distance, step_size, max_element, popped, total_time = run()
writer.writerow({"algorithm": "BFS with Euclidean", "distance": accepted / total_distance,
"step size": step_size, "max element": max_element, "popped": popped, "time": total_time})
elif j == 3:
gui.algorithm.set(1)
gui.evaluation.set(1)
total_distance, step_size, max_element, popped, total_time = run()
writer.writerow({"algorithm": "BFS with Manhattan", "distance": accepted / total_distance, "step size": step_size,
"max element": max_element, "popped": popped, "time": total_time})
elif j == 4:
gui.algorithm.set(2)
total_distance, step_size, max_element, popped, total_time = run()
writer.writerow({"algorithm": "DFS", "distance": accepted / total_distance, "step size": step_size,
"max element": max_element, "popped": popped, "time": total_time})
elif j == 5:
gui.algorithm.set(3)
total_distance, step_size, max_element, popped, total_time = run()
writer.writerow({"algorithm": "Breadth FS", "distance": accepted / total_distance, "step size": step_size,
"max element": max_element, "popped": popped, "time": total_time})
(12)在下面这段代码中,当直接运行程序时会创建一个tkinter 应用程序的根窗口 root,然后初始化一个名为 Gui 的对象 gui,最后启动 Tkinter 的事件循环以显示 GUI 界面。如果想要执行测试函数 test(),只需取消注释 test() 调用的行即可。
if __name__ == "__main__":
root = tk.Tk()
gui = Gui()
# test()
root.mainloop()
通过如下命令运行本项目,
python Project.py
在测试过程中可以尝试不同的组合,以确保程序在各种情况下都能够正确地执行,并产生预期的结果。我们可以尝试以下几种操作:
- 启用不同的算法:尝试分别选择A*、最佳优先搜索、深度优先搜索和广度优先搜索,观察它们的行为和结果有何不同。
- 调整速度设置:尝试不同的速度设置(快速、中等、慢速),观察动画效果的变化和程序执行的速度。
- 改变城市和连接数量:尝试不同数量的城市和连接,观察程序对于不同规模数据的处理能力。
- 测试随机数据生成:测试随机数据生成功能,观察生成的城市和连接是否符合预期,并且能否正确地运行路径搜索算法。
- 通过这些测试,可以确保程序在各种情况下都能够正常工作,并产生正确的输出结果。
例如设置10个“Cities”、20个“Connections”,使用“Best First Search”算法寻早最短路径的效果如图8-6所示。
图8-6 最短路径可视化
标签:distance,Search,based,max,gui,element,算法,time,total From: https://blog.csdn.net/asd343442/article/details/140719760