python实现dijstra算法(基于堆和循环桶)

目录

一.dijstra算法重述

1.基本思想:

2.基本的伪代码

3.正确性证明

4.dijstra的不同实现方式

4.1最直接的实现方式

4.2数组实现方式

4.3堆实现方式

数据结构堆的介绍:

4.4循环桶实现方式

二.python实现dijstra

1.基于数据结构堆实现dijstra

2.基于数据结构-循环桶实现dijstra


一.dijstra算法重述

1.基本思想:

基本思想:

1.从顶点s开始逐步扩展边界;

2.每次扩展,选择当前边界边中 满足贪心准则的边e(u*,v*); 确定s到v*的最短路径。 【加入点的被永久标记】

3.直至所有顶点均被永久标记。

2.基本的伪代码

X = {s}; //永久标记顶点集合
A[s]=0; //距离标记
B[s]=NULL; //路径
WHILE X 不等于 V  DO
   1) 选择边界边中A[u]+w(u,v)最小的边e(u*,v*);
    2) X = X U {v*};
    3) A[v*]=A[u*]+w(u*,v*);
    4) B[v*]=B[u*] U e(u*,v*); 
ENDWHILE

3.正确性证明

证明要求:

任给边权非负的有向加权图,Dijkstra算法都能正确计算所有的最短路距离。即: A[v]=D[v], ∀v∈V

其中A[v]代表:算法计算的距离

D[v]代表:真实的最短路的距离

下面是一个证明的连接:https://www.cs.auckland.ac.nz/software/AlgAnim/dij-proof.html

当然也可以跟随作者和作者老师的思路进行证明:

证明思路:对循环过程进行归纳证明。

基础步骤:A[s]=D[s]=0  成立。

归纳假设:以前的循环中,算法都是正确的。

即:∀v∈X, A[v]=D[v],且B[v]记录了真实最短路

归纳步骤:在归纳假设下证明当前循环结束时结果正确。

  注:上述图片来源于电子科技大学网路算法基础挑战性课程PPT 

  注:上述图片来源于电子科技大学网路算法基础挑战性课程PPT 

4.dijstra的不同实现方式

4.1最直接的实现方式

  注:上述图片来源于电子科技大学网路算法基础挑战性课程PPT 

4.2数组实现方式

1.用一个数据结构来维护所有 的边界点;

2.相当于所有边界边被分成不同 的小集合;

3.与同一个边界点相关联的那些 边只记录一个最小值。

伪代码:

FOR all vertex j in V DO
    A[j] = ; p[j] = NULL;
X = {s}; A[s]=0; p[s] = NULL; 
WHILE X  V  DO
    i = FindMin(V-X);
    X = X U {i};
    FOR every neighbor t of i
        IF A[i] + w(i, t) < A[t] 
            A[t] = A[i] + w(i, t); 
            p[t] = i;
    ENDFOR
ENDWHILE

4.3堆实现方式

与实现4.2类似,只是用堆来维护V-X集合,key为A值。

数据结构堆的介绍:

https://www.jianshu.com/p/6b526aa481b1

伪代码:

FOR all vertex j in V DO
    A[j] = ; p[j] = NULL;
X = {s}; A[s]=0; p[s] = NULL; 
WHILE X  V  DO
    i = FindMin(V-X);
    X = X U {i};
    FOR every neighbor t of i
        IF A[i] + w(i, t) < A[t] 
            A[t] = A[i] + w(i, t); 
            p[t] = i;
    ENDFOR
ENDWHILE

4.4循环桶实现方式

与实现4.2类似,但用桶来维护V-X集合。

数据结构桶:

https://www.jianshu.com/p/be7643cc073a

伪代码:

FOR all vertex j in V DO
    A[j] = ; p[j] = NULL;
X = {s}; A[s]=0; p[s] = NULL; 
WHILE X  V  DO
    i = FindMin(V-X);
    X = X U {i};
    FOR every neighbor t of i
        IF A[i] + w(i, t) < A[t] 
            A[t] = A[i] + w(i, t); 
            p[t] = i;
    ENDFOR
ENDWHILE

二.python实现dijstra

1.基于数据结构堆实现dijstra

from collections import defaultdict
data_edge=defaultdict(list)
nodes=[] #储存点


def build_graph(filepath,data_edge,nodes):#构造图
    f=open(filepath,'r')
    edge_num=int(f.readline())
    f.readline()
    for i in range(0,edge_num):
        node_a,node_b,edge_c=f.readline().split()
        data_edge[node_a].append((int(edge_c),node_a,node_b))
        if node_a not in nodes:
            nodes.append(node_a)
        if node_b not in nodes:
            nodes.append(node_b)
    start_node=f.readline().strip()#获取源点
    dis_node=f.readline().strip()#获取宿点
    f.close()
    return str(start_node),str(dis_node)


class heap(object):
    """堆"""
    def __init__(self):
        self.data=[]

    def get_parent_index(self,index):#获取父节点的下标
        if index==0 or index>len(self.data)-1:
            return None
        else:
            return (index-1)>>1

    def Exact_min(self):#取出最小值
        remove_data = self.data[0]
        self.data[0] = self.data[-1]
        del self.data[-1]
        self.heapify(self.data)# 将剩余数据堆化
        return remove_data

    def swap(self,index_a,index_b):#交换结点数据
        self.data[index_a], self.data[index_b]=self.data[index_b], self.data[index_a]

    def insert(self,data_key):#插入新来结点数据
        self.data.append(data_key)#先加到最后
        index=len(self.data)-1
        parent=self.get_parent_index(index)#先加入到堆的后面
        while parent is not None and self.data[parent][0]>=self.data[index][0]:# 交换操作
            self.swap(parent, index)
            index=parent
            parent=self.get_parent_index(parent)

    def heapify(self, arr):
            self.data=arr
            #print(arr)
            #print(self.data)
            index=self.get_parent_index(len(arr)-1)
            #print(index)
            while index!=None and index>=0  :
                if(2*index+1)<len(self.data):
                    if self.data[(2*index+1)]<self.data[index]:
                        self.swap(2*index+1,index)
                    if (2*index+2)<len(self.data) and (self.data[(2*index+2)]<self.data[index]):
                        self.swap(2*index+2,index)
                index=index-1

heap1=heap()


def dijkstra(data_edge,start_node,end_node,heap1):#
    distance=[]#记录已探索边界点和边界点最短距离
    path={}#保存与源点之间最短路路径数值
    path[start_node]=0#起始点的距离值初始化为0
    path_list=defaultdict(list)#存储每个点的路径
    visited=[]#记录一探索的节点的集合
    visited.append(start_node)
    path_list[start_node].append(start_node)
    for i in data_edge[start_node]:
        edge_c,node_a,node_b=i
        distance.append((edge_c,node_a,node_b))
        # path_list[node_b].append(node_a)
    heap1.heapify(distance)
    while end_node not in visited:
        present_min_distance,front_node,node=heap1.Exact_min()#选出距离最小的边数据
        for i in path_list[front_node]:#把它前面结点的路径加入新节点的路径中
            path_list[node].append(i)
        path_list[node].append(node)
        if node not in visited:
            visited.append(node)
            path[node]=present_min_distance
            for neighbor in data_edge[node]:#更新边集合
                edge_c,node,neighbor_node=neighbor
                present_min_distance=path[node]+edge_c
                if neighbor_node not in visited:
                    heap1.insert((present_min_distance,node,neighbor_node))#更新边界点
    return path,path_list#返回每个点距离源点源点最短路径的数值,和路径


a,b=build_graph('project5-test3',data_edge,nodes)
ans,ans_list=dijkstra(data_edge,a,b,heap1)
print("权重和:%d"%ans[b])#输出最短路径距离源点的最短路径
print('路径:')
print(ans_list[b])






2.基于数据结构-循环桶实现dijstra

from collections import defaultdict

class bucket(object):
    """循环桶"""
    def __init__(self,ration):
        self.ration=int(ration)#桶的容量
        # print(self.ration)
        self.data=[[] for i in range(0,int(ration))]
        self.front=1#桶前指针

    def insert(self,newdata):
        index=(newdata[0])%self.ration
        self.data[index].append(newdata)

    def Exact_min(self): #取出离桶前指针最近的桶中第一个元素
       while not self.data[(self.front)%self.ration]:
                  self.front=self.front+1
       key=self.data[self.front % self.ration][0]
       self.data[self.front % self.ration].pop(0)
       self.front=self.front+1
       return key

nodes=[]
edges=defaultdict(list)
edge_size=[]


def read_file(filepath,nodes,edges,edge_size):#读取文件数据
    f=open(filepath,'r')
    edge_num=int(f.readline())
    node_num=int(f.readline())
    for i in range(0,edge_num):
        node_a,node_b,edge_c=f.readline().split()
        edges[node_a].append((int(edge_c),node_a,node_b))
        edge_size.append(int(edge_c))
        if node_a not in nodes:
            nodes.append(node_a)
        if node_b not in nodes:
            nodes.append(node_b)
    start=f.readline().strip()
    end=f.readline().strip()
    f.close()
    return edge_num,node_num,start,end


def find_edge_max(edge_size):#找出最大边
    return max(edge_size)


def dijkstra(edges,start_node,bucket1,):
    path={}#存储每个点离源点的最短路径
    path[start_node]=0
    path_list = defaultdict(list)  # 存储每个点的路径
    visited=[]#已经永久标记过的点
    visited.append(start_node)
    path_list[start_node].append(start_node)
    for i in edges[start_node]:
        edge_c,start_node,node_next=i
        bucket1.insert((edge_c,start_node,node_next))
    while len(visited)!=len(nodes):
        min_current_distance,front_node,node=bucket1.Exact_min()
        for i in path_list[front_node]:#把它前面结点的路径加入新节点的路径中
            path_list[node].append(i)
        path_list[node].append(node)
        if node not in visited:
         path[node]=min_current_distance
         visited.append(node)
         for neighbor in edges[node]:
            if neighbor[2] not in visited:
                edge,node_a,node_b=neighbor
                current_distance=edge+path[node_a]
                bucket1.insert((current_distance,node_a,node_b))
    return path,path_list #返回各点最短权重和路径


a,b,c,d=read_file('project5-test3',nodes,edges,edge_size)
maxedge=find_edge_max(edge_size)
bucket1=bucket(find_edge_max(edge_size)+1)
ans,ans_list=dijkstra(edges,c,bucket1)
print("权重和:")
print(ans[d])
print("路径:")
print(ans_list[d])

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Dijkstra算法是一种用于图中寻找最短路径的算法,其基本思想是从起点开始,逐步扩展路径,直到到达终点为止。在扩展路径的过程中,会不断更新节点的最短路径和前驱节点。 下面给出Python实现Dijkstra算法的示例代码和输入输出: 示例输入: 图的邻接矩阵表示: ``` 0 10 inf inf inf inf 0 5 inf inf inf inf 0 1 inf inf inf inf 0 7 inf inf inf inf 0 ``` 起点和终点: ``` start = 0 end = 4 ``` 示例输出: ``` Shortest distance from 0 to 4 is 8 Path: [0, 1, 2, 3, 4] ``` 示例代码: ```python import heapq # Dijkstra算法 def dijkstra(graph, start, end): # 初始化距离和前驱节点 dist = [float('inf')] * len(graph) dist[start] = 0 prev = [-1] * len(graph) # 将起点加入中 heap = [(0, start)] while heap: # 弹出顶节点 (d, u) = heapq.heappop(heap) if u == end: # 到达终点,退出循环 break # 遍历相邻节点 for i, weight in enumerate(graph[u]): if weight != float('inf'): # 计算新的距离 new_dist = dist[u] + weight if new_dist < dist[i]: # 更新距离和前驱节点 dist[i] = new_dist prev[i] = u # 将节点加入中 heapq.heappush(heap, (new_dist, i)) # 构造路径 path = [] u = end while prev[u] != -1: path.insert(0, u) u = prev[u] path.insert(0, u) # 返回最短距离和路径 return dist[end], path # 测试 graph = [ [0, 10, float('inf'), float('inf'), float('inf')], [float('inf'), 0, 5, float('inf'), float('inf')], [float('inf'), float('inf'), 0, 1, float('inf')], [float('inf'), float('inf'), float('inf'), 0, 7], [float('inf'), float('inf'), float('inf'), float('inf'), 0] ] start = 0 end = 4 dist, path = dijkstra(graph, start, end) print(f"Shortest distance from {start} to {end} is {dist}") print(f"Path: {path}") ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个编程的菜鸡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值