ui_widget.py 作为主界面,paint_widget.py作为绘图界面,paintFunctions.py作为绘图函数。
总体架构是:ui_widget.py 调用 paint_widget.py 调用 paintFunctions.py
paintFunctions.py 返回各种搜索算法的close表给 paint_widget.py 进行绘图再呈现到 ui_widget.py
ui_widget.py主界面利用 pyside2 自带的 designer程序自动生成主界面代码(自己用designer设计生成的代码):
添加了绑定事件按钮等等东西,代码中带有注释的都是添加的。
# -*- coding: utf-8 -*-
import random
################################################################################
## Form generated from reading UI file 'widgetlJxbcV.ui'
##
## Created by: Qt User Interface Compiler version 5.15.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
from paintFunctions import GraphSearch
from paint_widget import PaintWidget
class Ui_my_widget(QMainWindow):
def __init__(self):
super(Ui_my_widget, self).__init__()
self.setupUi(self)
self.retranslateUi(self)
self.slot_init()
def setupUi(self, my_widget):
if not my_widget.objectName():
my_widget.setObjectName(u"my_widget")
my_widget.resize(685, 642)
my_widget.setFixedSize(650, 650)
self.paint_widget = PaintWidget()
self.paint_widget.setParent(my_widget)
self.paint_widget.setObjectName(u"paint_widget")
self.checkBox_A = QCheckBox(self.paint_widget)
self.checkBox_A.setObjectName(u"checkBox_17")
self.checkBox_A.setGeometry(QRect(92, 488, 30, 20))
self.checkBox_B = QCheckBox(self.paint_widget)
self.checkBox_B.setObjectName(u"checkBox_3")
self.checkBox_B.setGeometry(QRect(401, 323, 28, 20))
self.checkBox_C = QCheckBox(self.paint_widget)
self.checkBox_C.setObjectName(u"checkBox_4")
self.checkBox_C.setGeometry(QRect(254, 284, 28, 20))
self.checkBox_D = QCheckBox(self.paint_widget)
self.checkBox_D.setObjectName(u"checkBox_9")
self.checkBox_D.setGeometry(QRect(166, 295, 28, 20))
self.checkBox_E = QCheckBox(self.paint_widget)
self.checkBox_E.setObjectName(u"checkBox_2")
self.checkBox_E.setGeometry(QRect(563, 289, 28, 20))
self.checkBox_F = QCheckBox(self.paint_widget)
self.checkBox_F.setObjectName(u"checkBox_13")
self.checkBox_F.setGeometry(QRect(306, 445, 28, 20))
self.checkBox_G = QCheckBox(self.paint_widget)
self.checkBox_G.setObjectName(u"checkBox_10")
self.checkBox_G.setGeometry(QRect(376, 266, 28, 20))
self.checkBox_H = QCheckBox(self.paint_widget)
self.checkBox_H.setObjectName(u"checkBox_8")
self.checkBox_H.setGeometry(QRect(535, 346, 28, 20))
self.checkBox_I = QCheckBox(self.paint_widget)
self.checkBox_I.setObjectName(u"checkBox_6")
self.checkBox_I.setGeometry(QRect(474, 502, 28, 20))
self.checkBox_L = QCheckBox(self.paint_widget)
self.checkBox_L.setObjectName(u"checkBox_12")
self.checkBox_L.setGeometry(QRect(166, 375, 28, 20))
self.checkBox_M = QCheckBox(self.paint_widget)
self.checkBox_M.setObjectName(u"checkBox_7")
self.checkBox_M.setGeometry(QRect(169, 335, 28, 20))
self.checkBox_N = QCheckBox(self.paint_widget)
self.checkBox_N.setObjectName(u"checkBox_16")
self.checkBox_N.setGeometry(QRect(407, 533, 28, 20))
self.checkBox_O = QCheckBox(self.paint_widget)
self.checkBox_O.setObjectName(u"checkBox_15")
self.checkBox_O.setGeometry(QRect(132, 567, 28, 20))
self.checkBox_P = QCheckBox(self.paint_widget)
self.checkBox_P.setObjectName(u"checkBox_5")
self.checkBox_P.setGeometry(QRect(321, 364, 28, 20))
self.checkBox_R = QCheckBox(self.paint_widget)
self.checkBox_R.setObjectName(u"checkBox_14")
self.checkBox_R.setGeometry(QRect(234, 406, 28, 20))
self.checkBox_S = QCheckBox(self.paint_widget)
self.checkBox_S.setObjectName(u"checkBox_11")
self.checkBox_S.setGeometry(QRect(208, 453, 28, 20))
self.checkBox_T = QCheckBox(self.paint_widget)
self.checkBox_T.setObjectName(u"checkBox_20")
self.checkBox_T.setGeometry(QRect(95, 406, 30, 20))
self.checkBox_U = QCheckBox(self.paint_widget)
self.checkBox_U.setObjectName(u"checkBox_19")
self.checkBox_U.setGeometry(QRect(457, 346, 30, 20))
self.checkBox_V = QCheckBox(self.paint_widget)
self.checkBox_V.setObjectName(u"checkBox_18")
self.checkBox_V.setGeometry(QRect(510, 440, 30, 20))
self.checkBox_Z = QCheckBox(self.paint_widget)
self.checkBox_Z.setObjectName(u"checkBox_21")
self.checkBox_Z.setGeometry(QRect(109, 527, 30, 20))
self.layoutWidget = QWidget(my_widget)
self.layoutWidget.setObjectName(u"layoutWidget")
self.layoutWidget.setGeometry(QRect(41, 6, 569, 231))
self.verticalLayout = QVBoxLayout(self.layoutWidget)
self.verticalLayout.setObjectName(u"verticalLayout")
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.btn_deepth = QPushButton(self.layoutWidget)
self.btn_deepth.setObjectName(u"btn_deepth")
self.btn_deepth.setMinimumSize(QSize(40, 40))
self.btn_deepth.setMaximumSize(QSize(100, 40))
self.horizontalLayout.addWidget(self.btn_deepth)
self.btn_width = QPushButton(self.layoutWidget)
self.btn_width.setObjectName(u"btn_width")
self.btn_width.setMinimumSize(QSize(40, 40))
self.btn_width.setMaximumSize(QSize(100, 40))
self.horizontalLayout.addWidget(self.btn_width)
self.btn_greedy = QPushButton(self.layoutWidget)
self.btn_greedy.setObjectName(u"btn_greedy")
self.btn_greedy.setMinimumSize(QSize(40, 40))
self.btn_greedy.setMaximumSize(QSize(100, 40))
self.horizontalLayout.addWidget(self.btn_greedy)
self.btn_Astar = QPushButton(self.layoutWidget)
self.btn_Astar.setObjectName(u"btn_Astar")
self.btn_Astar.setMinimumSize(QSize(40, 40))
self.btn_Astar.setMaximumSize(QSize(100, 40))
self.horizontalLayout.addWidget(self.btn_Astar)
self.btn_clear = QPushButton(self.layoutWidget)
self.btn_clear.setObjectName(u"btn_clear")
self.btn_clear.setMinimumSize(QSize(40, 40))
self.btn_clear.setMaximumSize(QSize(100, 40))
self.horizontalLayout.addWidget(self.btn_clear)
self.verticalLayout.addLayout(self.horizontalLayout)
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.verticalLayout.addItem(self.verticalSpacer)
self.horizontalLayout_2 = QHBoxLayout()
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
self.listView_3 = QTextBrowser(self.layoutWidget)
self.listView_3.setObjectName(u"listView_3")
self.horizontalLayout_2.addWidget(self.listView_3)
self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.horizontalLayout_2.addItem(self.horizontalSpacer)
self.listView_2 = QTextBrowser(self.layoutWidget)
self.listView_2.setObjectName(u"listView_2")
self.horizontalLayout_2.addWidget(self.listView_2)
self.verticalLayout.addLayout(self.horizontalLayout_2)
# 获取所有的checkbox
self.list = self.paint_widget.findChildren(QCheckBox)
# 计数器 保证每次只能两个
self.count = 0
self.retranslateUi(my_widget)
QMetaObject.connectSlotsByName(my_widget)
# setupUi
def retranslateUi(self, my_widget):
my_widget.setWindowTitle(QCoreApplication.translate("my_widget", u"罗马尼亚度假问题", None))
self.checkBox_I.setText(QCoreApplication.translate("my_widget", u"I", None))
self.checkBox_L.setText(QCoreApplication.translate("my_widget", u"L", None))
self.checkBox_V.setText(QCoreApplication.translate("my_widget", u"V", None))
self.checkBox_B.setText(QCoreApplication.translate("my_widget", u"B", None))
self.checkBox_Z.setText(QCoreApplication.translate("my_widget", u"Z", None))
self.checkBox_M.setText(QCoreApplication.translate("my_widget", u"M", None))
self.checkBox_E.setText(QCoreApplication.translate("my_widget", u"E", None))
self.checkBox_G.setText(QCoreApplication.translate("my_widget", u"G", None))
self.checkBox_C.setText(QCoreApplication.translate("my_widget", u"C", None))
self.checkBox_S.setText(QCoreApplication.translate("my_widget", u"S", None))
self.checkBox_O.setText(QCoreApplication.translate("my_widget", u"O", None))
self.checkBox_D.setText(QCoreApplication.translate("my_widget", u"D", None))
self.checkBox_P.setText(QCoreApplication.translate("my_widget", u"P", None))
self.btn_width.setText(QCoreApplication.translate("my_widget", u"\u5e7f\u5ea6\u4f18\u5148\u641c\u7d22", None))
self.btn_deepth.setText(QCoreApplication.translate("my_widget", u"\u6df1\u5ea6\u4f18\u5148\u641c\u7d22", None))
self.btn_greedy.setText(QCoreApplication.translate("my_widget", u"\u8d2a\u5a6a\u7b97\u6cd5", None))
self.btn_Astar.setText(QCoreApplication.translate("my_widget", u"A*\u7b97\u6cd5", None))
self.btn_clear.setText(QCoreApplication.translate("my_widget", u"\u6e05\u9664", None))
self.checkBox_N.setText(QCoreApplication.translate("my_widget", u"N", None))
self.checkBox_F.setText(QCoreApplication.translate("my_widget", u"F", None))
self.checkBox_A.setText(QCoreApplication.translate("my_widget", u"A", None))
self.checkBox_H.setText(QCoreApplication.translate("my_widget", u"H", None))
self.checkBox_T.setText(QCoreApplication.translate("my_widget", u"T", None))
self.checkBox_R.setText(QCoreApplication.translate("my_widget", u"R", None))
self.checkBox_U.setText(QCoreApplication.translate("my_widget", u"U", None))
def slot_init(self):
# 绑定事件
self.btn_width.clicked.connect(lambda: self.BFS())
self.btn_deepth.clicked.connect(lambda: self.DFS())
self.btn_greedy.clicked.connect(lambda: self.greedySearch())
self.btn_Astar.clicked.connect(lambda: self.AstarSearch())
self.btn_clear.clicked.connect(lambda: self.clearAll())
for i in self.list:
i.clicked.connect(lambda: self.checkBtn())
def BFS(self):
# self.findStartAndEnd()
if self.paint_widget.start == "" or self.paint_widget.end == "":
msg_box = QMessageBox(QMessageBox.Warning, 'Warning', '请先选择起点和终点!')
msg_box.exec_()
return
self.paint_widget.gs = GraphSearch(self.paint_widget.start,
self.paint_widget.end) # 第一个参数是起点城市名的首字母 第二个是终点城市名的首字母
self.paint_widget.gs.constructGraph() # 构建城市图
self.paint_widget.graph = self.paint_widget.gs.graph
self.paint_widget.gs.widthFirstSearch()
self.paint_widget.type = 0
self.paint_widget.update()
self.printPath(self.paint_widget.gs.close_width)
pass
def DFS(self):
# self.findStartAndEnd()
if self.paint_widget.start == "" or self.paint_widget.end == "":
msg_box = QMessageBox(QMessageBox.Warning, 'Warning', '请先选择起点和终点!')
msg_box.exec_()
return
self.paint_widget.gs = GraphSearch(self.paint_widget.start,
self.paint_widget.end) # 第一个参数是起点城市名的首字母 第二个是终点城市名的首字母
self.paint_widget.gs.constructGraph() # 构建城市图
self.paint_widget.graph = self.paint_widget.gs.graph
self.paint_widget.gs.deepFirstSearch()
self.paint_widget.type = 1
self.paint_widget.update()
self.printPath(self.paint_widget.gs.close_deepth)
pass
def greedySearch(self):
if self.paint_widget.start == "" or self.paint_widget.end == "":
msg_box = QMessageBox(QMessageBox.Warning, 'Warning', '请先选择起点和终点!')
msg_box.exec_()
return
# self.findStartAndEnd()
self.paint_widget.gs = GraphSearch(self.paint_widget.start,
self.paint_widget.end) # 第一个参数是起点城市名的首字母 第二个是终点城市名的首字母
self.paint_widget.gs.constructGraph() # 构建城市图
self.paint_widget.graph = self.paint_widget.gs.graph
self.paint_widget.gs.greedSearch()
self.paint_widget.type = 2
self.paint_widget.update()
self.printPath(self.paint_widget.gs.close_greed)
pass
def AstarSearch(self):
if self.paint_widget.start == "" or self.paint_widget.end == "":
msg_box = QMessageBox(QMessageBox.Warning, 'Warning', '请先选择起点和终点!')
msg_box.exec_()
return
self.paint_widget.gs = GraphSearch(self.paint_widget.start,
self.paint_widget.end) # 第一个参数是起点城市名的首字母 第二个是终点城市名的首字母
self.paint_widget.gs.constructGraph() # 构建城市图
self.paint_widget.graph = self.paint_widget.gs.graph
self.paint_widget.gs.AstarAlgorithm()
self.paint_widget.type = 3
self.paint_widget.update()
self.printPath(self.paint_widget.gs.close_Astar)
pass
def clearAll(self):
self.paint_widget.type = -1
self.paint_widget.update()
self.listView_2.setText("")
self.listView_3.setText("")
self.count = 0
for i in self.list:
i.setChecked(False)
pass
def checkBtn(self):
for i in self.list:
if i.isChecked():
if i.text() != self.paint_widget.start:
if self.count == 0:
self.paint_widget.start = i.text()
self.count += 1
if i.text() != self.paint_widget.start and self.count == 2:
self.paint_widget.end = i.text()
if self.count > 2:
self.count = 0
for i in self.list:
i.setChecked(False)
msg_box = QMessageBox(QMessageBox.Warning, 'Warning', '您选择的点太多!')
msg_box.exec_()
self.clearAll()
return
# def findStartAndEnd(self):
# count = 0
# for i in self.list:
# if i.isChecked():
# if count == 0:
# self.paint_widget.start = i.text()
# count = 1
#
# continue
# elif count == 1:
# self.paint_widget.end = i.text()
def printPath(self, close):
endNode = close[-1]
path = [endNode.name]
# 从终点向前找
while path[-1] != self.paint_widget.gs.start:
if endNode.prev:
path.append(endNode.prev.name)
endNode = endNode.prev
path.reverse()
self.listView_2.setText("搜索路径:" + str(path))
close1 = []
for i in close:
close1.append(i.name)
self.listView_3.setText("close表:" + str(close1))
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
ui = Ui_my_widget()
ui.show()
sys.exit(app.exec_())
import functools
import math
import matplotlib.pyplot as plt
from collections import deque
from Graph import Graph, Node
from test import Test
class GraphSearch():
def __init__(self, start='A', end='B'):
self.start = start
self.end = end
# cities是一个字典 第一个表示城市坐标,第二个list表示相邻城市及其路径权重
self.cities = {'A': [(91, 492), [['Z', 75], ['T', 118], ['S', 140]]],
'B': [(400, 327), [['U', 85], ['G', 90], ['P', 101], ['F', 211]]],
'C': [(253, 288), [['D', 120], ['P', 138], ['R', 146]]],
'D': [(165, 299), [['M', 75], ['C', 120]]],
'E': [(562, 293), [['H', 86]]],
'F': [(305, 449), [['S', 99], ['B', 211]]],
'G': [(375, 270), [['B', 90]]],
'H': [(534, 350), [['E', 86], ['U', 98]]],
'I': [(473, 506), [['N', 87], ['V', 92]]],
'L': [(165, 379), [['M', 70], ['T', 111]]],
'M': [(168, 339), [['L', 70], ['D', 75]]],
'N': [(406, 537), [['I', 87]]],
'O': [(131, 571), [['Z', 71], ['S', 151]]],
'P': [(320, 368), [['R', 97], ['B', 101], ['C', 138]]],
'R': [(233, 410), [['S', 80], ['P', 97], ['C', 146]]],
'S': [(207, 457), [['R', 80], ['F', 99], ['A', 140], ['O', 151]]],
'T': [(94, 410), [['L', 111], ['A', 118]]],
'U': [(456, 350), [['B', 85], ['H', 98], ['V', 142]]],
'V': [(509, 444), [['I', 92], ['U', 142]]],
'Z': [(108, 531), [['O', 71], ['A', 75]]]}
self.graph = Graph()
self.close_width = []
self.open_width = []
self.close_deepth = 0
self.close_greed = 0
self.close_Astar = 0
def constructGraph(self):
for i in self.cities:
# print(i, self.cities[i])
node = Node()
node.name = i
node.point = self.cities[i][0]
node.next = self.cities[i][1] # 包含了 邻居城市与它们之间的距离
self.graph.nodes.append(node)
def printPath(self, close):
endNode = close[-1]
path = [endNode.name]
# 从终点向前找
while path[-1] != self.start:
if endNode.prev:
path.append(endNode.prev.name)
endNode = endNode.prev
path.reverse()
print("搜索路径为:", path)
print("close表为:", end=" ")
for i in close:
print(i.name, end=" ")
print()
def widthFirstSearch(self):
startNode = Node()
endNode = Node()
for i in self.graph.nodes:
if i.name == self.start:
startNode = i
if i.name == self.end:
endNode = i
close = []
open = deque()
open.append(startNode)
while open:
city = open.popleft()
if city not in close:
close.append(city)
if city == endNode:
self.close_width = close
self.open_width = open
return
for i in city.next:
for j in self.graph.nodes:
if i[0] == j.name:
i = j
if i not in open and i not in close: # 结点i既不在open表 又不在close表,代表它没有被访问过,
i.prev = city
open.append(i) # 只有没有被访问过的邻居,我们才将它加入open表中进行下一步操作
break
def deepFirstSearch(self):
startNode = Node()
endNode = Node()
for i in self.graph.nodes:
if i.name == self.start:
startNode = i
if i.name == self.end:
endNode = i
close = []
open = [] # 模拟堆栈
open.append(startNode)
while open:
city = open.pop()
if city not in close:
close.append(city)
if city == endNode:
self.close_deepth = close
return
for i in reversed(city.next):
for j in self.graph.nodes:
if i[0] == j.name:
i = j
if i not in close:
i.prev = city
open.append(i)
break
def greedSearch(self):
startNode = Node()
endNode = Node()
for i in self.graph.nodes:
if i.name == self.start:
startNode = i
if i.name == self.end:
endNode = i
close = []
open = deque()
open.append(startNode)
while open:
open = sorted(open, key=functools.cmp_to_key(self.compareValue))
# open.sort(key=functools.cmp_to_key(self.compareValue))
city = open.pop()
if city not in close:
close.append(city)
if city == endNode:
# print("\n贪婪搜索路径为:")
# self.printPath(close)
# print("贪婪搜索close表为:")
# for i in close:
# print(i.name, end=" ")
# print("\n搜索总代价为:", close[-1].gn)
self.close_greed = close
return
for i in city.next:
for j in self.graph.nodes:
if i[0] == j.name:
cost = i[1]
i = j
if i not in open and i not in close:
i.prev = city # 更新前置结点之前判断是否路径更佳,而不是简单的判断是否被访问
open.append(i) # append是浅拷贝
while i.prev:
for j in i.next:
if j[0] == i.prev.name:
i.gn = j[1] + i.prev.gn
i = i.prev
break
elif i.gn > (city.gn + cost):
i.prev = city # 更新前置结点之前判断是否路径更佳,而不是简单的判断是否被访问
open.append(i) # append是浅拷贝
while i.prev:
for j in i.next:
if j[0] == i.prev.name:
i.gn = j[1] + i.prev.gn
i = i.prev
break
break
def AstarAlgorithm(self):
# 计算城市图每个点到终点城市的距离,获取h(n):节点n距离终点的预计代价,也就是A*算法的启发函数
distance = {}
startNode = Node()
endNode = Node()
for i in self.graph.nodes:
distance[i.name] = math.sqrt(pow(i.point[0] - self.cities[self.end][0][0], 2) + \
pow(i.point[1] - self.cities[self.end][0][1], 2))
if i.name == self.start:
startNode = i
if i.name == self.end:
endNode = i
close = []
open = deque()
open.append(startNode)
while open:
# 对open表排序
open = deque(sorted(open, key=functools.cmp_to_key(self.compareNode)))
city = open.popleft()
# city结点不在close里面则扩展
if city not in close:
close.append(city)
if city == endNode:
self.close_Astar = close
return
for i in city.next:
for j in self.graph.nodes:
if i[0] == j.name:
cost = i[1]
i = j
if i not in open and i not in close:
# 判断是否被访问
i.prev = city
# print(f"{i.name}<-{city.name}")
open.append(i)
# 计算当前结点到起点已经走过的代价并且加上欧式距离 获取f(n)=g(n)+h(n)
# g(n):节点n距离起点的代价 这个代价是已知的,只需要把走过的路花费的代价加起来
while i.prev:
for j in i.next:
if j[0] == i.prev.name:
i.gn = j[1] + i.prev.gn
i.fn = i.gn + distance[i.name]
i = i.prev
break
elif i.gn > (city.gn + cost):
i.prev = city # 更新前置结点之前判断是否路径更佳,而不是简单的判断是否被访问
# print(f"{i.name}<-{city.name}")
open.append(i) # append是浅拷贝
while i.prev:
for j in i.next:
if j[0] == i.prev.name:
i.gn = j[1] + i.prev.gn
i.fn = i.gn + distance[i.name]
i = i.prev
break
break
def compareValue(self, node1, node2):
# 小的排右边
if node1.gn < node2.gn:
return 1
elif node1.gn > node2.gn:
return -1
else:
return 0
def compareNode(self, node1, node2):
if node1.fn > node2.fn:
return 1
elif node1.fn < node2.fn:
return -1
else:
# fn相等按gn算
if node1.gn > node2.gn:
return 1
else:
return -1
import functools
import math
import matplotlib.pyplot as plt
from collections import deque
from Graph import Graph, Node
from test import Test
class GraphSearch():
def __init__(self, start='A', end='B'):
self.start = start
self.end = end
# cities是一个字典 第一个表示城市坐标,第二个list表示相邻城市及其路径权重
self.cities = {'A': [(91, 492), [['Z', 75], ['T', 118], ['S', 140]]],
'B': [(400, 327), [['U', 85], ['G', 90], ['P', 101], ['F', 211]]],
'C': [(253, 288), [['D', 120], ['P', 138], ['R', 146]]],
'D': [(165, 299), [['M', 75], ['C', 120]]],
'E': [(562, 293), [['H', 86]]],
'F': [(305, 449), [['S', 99], ['B', 211]]],
'G': [(375, 270), [['B', 90]]],
'H': [(534, 350), [['E', 86], ['U', 98]]],
'I': [(473, 506), [['N', 87], ['V', 92]]],
'L': [(165, 379), [['M', 70], ['T', 111]]],
'M': [(168, 339), [['L', 70], ['D', 75]]],
'N': [(406, 537), [['I', 87]]],
'O': [(131, 571), [['Z', 71], ['S', 151]]],
'P': [(320, 368), [['R', 97], ['B', 101], ['C', 138]]],
'R': [(233, 410), [['S', 80], ['P', 97], ['C', 146]]],
'S': [(207, 457), [['R', 80], ['F', 99], ['A', 140], ['O', 151]]],
'T': [(94, 410), [['L', 111], ['A', 118]]],
'U': [(456, 350), [['B', 85], ['H', 98], ['V', 142]]],
'V': [(509, 444), [['I', 92], ['U', 142]]],
'Z': [(108, 531), [['O', 71], ['A', 75]]]}
self.graph = Graph()
self.close_width = []
self.open_width = []
self.close_deepth = 0
self.close_greed = 0
self.close_Astar = 0
def constructGraph(self):
for i in self.cities:
# print(i, self.cities[i])
node = Node()
node.name = i
node.point = self.cities[i][0]
node.next = self.cities[i][1] # 包含了 邻居城市与它们之间的距离
self.graph.nodes.append(node)
def printPath(self, close):
endNode = close[-1]
path = [endNode.name]
# 从终点向前找
while path[-1] != self.start:
if endNode.prev:
path.append(endNode.prev.name)
endNode = endNode.prev
path.reverse()
print("搜索路径为:", path)
print("close表为:", end=" ")
for i in close:
print(i.name, end=" ")
print()
def widthFirstSearch(self):
startNode = Node()
endNode = Node()
for i in self.graph.nodes:
if i.name == self.start:
startNode = i
if i.name == self.end:
endNode = i
close = []
open = deque()
open.append(startNode)
while open:
city = open.popleft()
if city not in close:
close.append(city)
if city == endNode:
self.close_width = close
self.open_width = open
return
for i in city.next:
for j in self.graph.nodes:
if i[0] == j.name:
i = j
if i not in open and i not in close: # 结点i既不在open表 又不在close表,代表它没有被访问过,
i.prev = city
open.append(i) # 只有没有被访问过的邻居,我们才将它加入open表中进行下一步操作
break
def deepFirstSearch(self):
startNode = Node()
endNode = Node()
for i in self.graph.nodes:
if i.name == self.start:
startNode = i
if i.name == self.end:
endNode = i
close = []
open = [] # 模拟堆栈
open.append(startNode)
while open:
city = open.pop()
if city not in close:
close.append(city)
if city == endNode:
self.close_deepth = close
return
for i in reversed(city.next):
for j in self.graph.nodes:
if i[0] == j.name:
i = j
if i not in close:
i.prev = city
open.append(i)
break
def greedSearch(self):
startNode = Node()
endNode = Node()
for i in self.graph.nodes:
if i.name == self.start:
startNode = i
if i.name == self.end:
endNode = i
close = []
open = deque()
open.append(startNode)
while open:
open = sorted(open, key=functools.cmp_to_key(self.compareValue))
# open.sort(key=functools.cmp_to_key(self.compareValue))
city = open.pop()
if city not in close:
close.append(city)
if city == endNode:
# print("\n贪婪搜索路径为:")
# self.printPath(close)
# print("贪婪搜索close表为:")
# for i in close:
# print(i.name, end=" ")
# print("\n搜索总代价为:", close[-1].gn)
self.close_greed = close
return
for i in city.next:
for j in self.graph.nodes:
if i[0] == j.name:
cost = i[1]
i = j
if i not in open and i not in close:
i.prev = city # 更新前置结点之前判断是否路径更佳,而不是简单的判断是否被访问
open.append(i) # append是浅拷贝
while i.prev:
for j in i.next:
if j[0] == i.prev.name:
i.gn = j[1] + i.prev.gn
i = i.prev
break
elif i.gn > (city.gn + cost):
i.prev = city # 更新前置结点之前判断是否路径更佳,而不是简单的判断是否被访问
open.append(i) # append是浅拷贝
while i.prev:
for j in i.next:
if j[0] == i.prev.name:
i.gn = j[1] + i.prev.gn
i = i.prev
break
break
def AstarAlgorithm(self):
# 计算城市图每个点到终点城市的距离,获取h(n):节点n距离终点的预计代价,也就是A*算法的启发函数
distance = {}
startNode = Node()
endNode = Node()
for i in self.graph.nodes:
distance[i.name] = math.sqrt(pow(i.point[0] - self.cities[self.end][0][0], 2) + \
pow(i.point[1] - self.cities[self.end][0][1], 2))
if i.name == self.start:
startNode = i
if i.name == self.end:
endNode = i
close = []
open = deque()
open.append(startNode)
while open:
# 对open表排序
open = deque(sorted(open, key=functools.cmp_to_key(self.compareNode)))
city = open.popleft()
# city结点不在close里面则扩展
if city not in close:
close.append(city)
if city == endNode:
self.close_Astar = close
return
for i in city.next:
for j in self.graph.nodes:
if i[0] == j.name:
cost = i[1]
i = j
if i not in open and i not in close:
# 判断是否被访问
i.prev = city
# print(f"{i.name}<-{city.name}")
open.append(i)
# 计算当前结点到起点已经走过的代价并且加上欧式距离 获取f(n)=g(n)+h(n)
# g(n):节点n距离起点的代价 这个代价是已知的,只需要把走过的路花费的代价加起来
while i.prev:
for j in i.next:
if j[0] == i.prev.name:
i.gn = j[1] + i.prev.gn
i.fn = i.gn + distance[i.name]
i = i.prev
break
elif i.gn > (city.gn + cost):
i.prev = city # 更新前置结点之前判断是否路径更佳,而不是简单的判断是否被访问
# print(f"{i.name}<-{city.name}")
open.append(i) # append是浅拷贝
while i.prev:
for j in i.next:
if j[0] == i.prev.name:
i.gn = j[1] + i.prev.gn
i.fn = i.gn + distance[i.name]
i = i.prev
break
break
def compareValue(self, node1, node2):
# 小的排右边
if node1.gn < node2.gn:
return 1
elif node1.gn > node2.gn:
return -1
else:
return 0
def compareNode(self, node1, node2):
if node1.fn > node2.fn:
return 1
elif node1.fn < node2.fn:
return -1
else:
# fn相等按gn算
if node1.gn > node2.gn:
return 1
else:
return -1
以上全部代码都开源在了github上:https://github.com/Infinityay/SearchAlgorithm. 如果对你有帮助,希望能给我点个Star, 蟹蟹!
当然你也可以去我的个人博客看看 生有涯知无涯