算法-狄克斯特拉算法

狄克斯特拉算法用于在加权图中查找最短路径

狄克斯拉特算法

迪杰斯特拉算法主要特点是从起始点开始,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。

以下图为例,演示如何实现狄克斯特拉算法:

1.需要3个散列表:

graph                        # 实现图,并显示边的权重

costs                        # 储存每个节点的开销

parents                        # 储存父节点

2.代码分别如下:
 

# 创建一个散列表记录节点的邻居,再创建一个散列表记录边的权重
graph = dict()
graph["start"] = {}
graph["start"]["a"] = 6         # 起点start节点的邻居
graph["start"]["b"] = 2

print("起始节点的邻居及边的权重:", graph["start"])           # 如果要获取起始节点的所有邻居和边的权重,可以这么做
print("起始节点的所有邻居:", graph["start"].keys())           # 获取所有邻居
print("起始节点到’a‘节点的边的权重:", graph["start"]["a"])              # 获取边的权重
print("\n")

graph["a"] = {}
graph["a"]["fin"] = 1           # a节点的邻居
graph["b"] = {}
graph["b"]["a"] = 3
graph["b"]["fin"] = 5
graph["fin"] = {}           # 终点fin节点没有邻居
# 创建开销表
infinity = float("inf")         # 表示无穷大
costs = dict()
costs["a"] = 6
costs["b"] = 2
costs["fin"] = infinity
# 储存父节点
parents = dict()
parents["a"] = "start"
parents["b"] = "start"
parents["fin"] = None

3.狄克斯特拉算法思路:

        

狄克斯拉特算法
1有节点要处理
2获取最近节点
3更新邻居开销表
4同时更新父节点
5标记为处理过
6再返回第一步
node = find_lowest_cost_node(costs)         # 找出未处理的开销最小的节点
while node is not None:         # 所有节点都被处理过
    cost = costs[node]
    neighbors = graph[node]
    for n in neighbors.keys():
        new_cost = cost + neighbors[n]
        if costs[n] > new_cost:         # 如果新节点更近,则更新开销表
            costs[n] = new_cost
            parents[n] = node
    processed.append(node)          # 标记为处理过
    node = find_lowest_cost_node(costs)

4.找开销最低节点

def find_lowest_cost_node(costs):
    lowest_cost = float("inf")
    lowest_cost_node = None
    for node in costs:
        cost = costs[node]
        if cost < lowest_cost and node not in processed:
            lowest_cost = cost
            lowest_cost_node = node
    return lowest_cost_node
"""
狄克斯拉特算法

寻找有权图中(没有权重为负的边情况下)权重最小的路径

"""

# 创建一个散列表记录节点的邻居,再创建一个散列表记录边的权重
graph = dict()
graph["start"] = {}
graph["start"]["a"] = 6         # 起点start节点的邻居
graph["start"]["b"] = 2

print("起始节点的邻居及边的权重:", graph["start"])           # 如果要获取起始节点的所有邻居和边的权重,可以这么做
print("起始节点的所有邻居:", graph["start"].keys())           # 获取所有邻居
print("起始节点到’a‘节点的边的权重:", graph["start"]["a"])              # 获取边的权重
print("\n")

graph["a"] = {}
graph["a"]["fin"] = 1           # a节点的邻居
graph["b"] = {}
graph["b"]["a"] = 3
graph["b"]["fin"] = 5
graph["fin"] = {}           # 终点fin节点没有邻居

# 创建开销表
infinity = float("inf")         # 表示无穷大
costs = dict()
costs["a"] = 6
costs["b"] = 2
costs["fin"] = infinity

# 储存父节点
parents = dict()
parents["a"] = "start"
parents["b"] = "start"
parents["fin"] = None

processed = []          # 处理过的节点不再处理(没有权重为负的边,结果才能保证正确)


def find_lowest_cost_node(costs):
    lowest_cost = float("inf")
    lowest_cost_node = None
    for node in costs:
        cost = costs[node]
        if cost < lowest_cost and node not in processed:
            lowest_cost = cost
            lowest_cost_node = node
    return lowest_cost_node


node = find_lowest_cost_node(costs)         # 找出未处理的开销最小的节点
while node is not None:         # 所有节点都被处理过
    cost = costs[node]
    neighbors = graph[node]
    for n in neighbors.keys():
        new_cost = cost + neighbors[n]
        if costs[n] > new_cost:         # 如果新节点更近,则更新开销表
            costs[n] = new_cost
            parents[n] = node
    processed.append(node)          # 标记为处理过
    node = find_lowest_cost_node(costs)
print("起点到终点最小开销为:", cost)

最终代码

class DijkstraAlgorithm:
    def __init__(self, graph):
        self.graph = graph

    def find_lowest_cost_node(self, costs, processed):
        lowest_cost = float("inf")
        lowest_cost_node = None
        for node in costs:
            cost = costs[node]
            if cost < lowest_cost and node not in processed:
                lowest_cost = cost
                lowest_cost_node = node
        return lowest_cost_node

    def find_shortest_path(self, start, end):
        infinity = float("inf")

        # 初始化开销表、父节点和处理过的节点列表
        costs = {node: infinity for node in self.graph}
        costs[start] = 0
        parents = {node: None for node in self.graph}
        processed = []

        # 查找最短路径
        node = self.find_lowest_cost_node(costs, processed)
        while node is not None:
            cost = costs[node]
            neighbors = self.graph[node]
            for neighbor in neighbors:
                new_cost = cost + neighbors[neighbor]
                if costs[neighbor] > new_cost:
                    costs[neighbor] = new_cost
                    parents[neighbor] = node

            processed.append(node)
            print(f"节点{node}已被处理过")
            print(f"开销表更新为:{costs}")

            node = self.find_lowest_cost_node(costs, processed)

        # 输出最短路径和总开销
        path = []
        current = end
        while current != start:
            path.insert(0, current)
            current = parents[current]
        path.insert(0, start)

        return path, costs[end]


# 测试
if __name__ == "__main__":            # 图的简化代码
    graph = {
        "start": {"a": 6, "b": 2},
        "a": {"fin": 1},
        "b": {"a": 3, "fin": 5},
        "fin": {}
    }

    algorithm = DijkstraAlgorithm(graph)
    shortest_path, total_cost = algorithm.find_shortest_path("start", "fin")
    print("最短路径:", shortest_path)
    print("总开销:", total_cost)

结果

  • 24
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值