常用的单源最短路径算法一共有两个,一个是Dijkstra算法 ,一个是Bellman-ford 算法
Dijkstra 算法 不能处理含有负权边的图,Bellmanford 能够处理含负权边或包含负权回路的图。
首先是Dijkstra算法:
算法的具体思想就不多写了,算法导论上有很详细的介绍,我主要还是贴出一个代码实现。
Dijstra里面需要用到优先级队列这里笔者也给出了一个。
使用堆实现的优先级队列,Dijkstar的复杂度在VlogV。
优先队列:
package graphic; import java.util.ArrayList; import java.util.Comparator; import java.util.List; public class PriorityQueue<E> { private final static int ROOT_INDEX =0; private List<E> heap ; protected Comparator<E> comparator; public PriorityQueue() { heap = new ArrayList<E>(); } public PriorityQueue(Comparator<E> comparator){ this.comparator = comparator; heap = new ArrayList<E>(); } public void insert(E obj){ heap.add(obj); int index = heap.size()-1; adjustHeapUP(index); } public void decreaseKey(E obj){ for(int i =0;i<heap.size();i++){ E cur = heap.get(i); if(cur.equals(obj)){ adjustHeapUP(i); break; } } } public E extractMin(){ if(heap.isEmpty()){throw new RuntimeException();} int index = heap.size()-1; E min = heap.get(ROOT_INDEX); E last = heap.get(index); heap.set(ROOT_INDEX, last); heap.remove(index); adjustHeapDown(ROOT_INDEX); return min; } protected void adjustHeapDown(int index){ int p = index; int target = 2*p+1; if(target >= heap.size())return; if(target+1 < heap.size() && compare(heap.get(target),heap.get(target+1)) >0 ){ target ++; } E paret = heap.get(p); E t = heap.get(target); if(compare(paret, t) > 0){ heap.set(p, t); heap.set(target, paret); adjustHeapDown(target); } } protected int compare(E src,E des){ if(comparator==null){ Comparable<E> s1 = (Comparable<E>)src; Comparable<E> s2 = (Comparable<E>)des; return s1.compareTo((E) s2); }else{ return comparator.compare(src, des); } } protected void adjustHeapUP(int index){ int parent = parent(index); E p = heap.get(parent); E cur = heap.get(index); if(compare(cur,p)<0){ heap.set(index, p); heap.set(parent, cur); adjustHeapUP(parent); } } public void print(){ for(E e:heap){ System.out.println(e); } System.out.println(); } protected int parent(int index){ return (index-1)/2; } public boolean isEmpty(){ return heap.isEmpty(); } }
Dijkstra算法:
package graphic; import java.util.List; public class Dijkstra { static int NODE_NUM =0 ; GNode[] nodes ; PriorityQueue<GNode> queue = new PriorityQueue<GNode>(); public void addNode(int[] ids){ NODE_NUM = ids.length; nodes = new GNode[NODE_NUM+1]; for(Integer id:ids){ nodes[id] = new GNode(id); } } public void addDirectionEdge(int src,int des,int weight){ GEdge edge = new GEdge(nodes[src],nodes[des],weight); nodes[src].edges.add(edge); } public void addUnDirectedEdge(int src,int des,int weight){ addDirectionEdge(src,des,weight); addDirectionEdge(des,src,weight); } public void shortPath(int src,int des){ nodes[src].dis=0; for(int i=1;i<nodes.length;i++){ queue.insert(nodes[i]); } while(!queue.isEmpty()){ GNode min = queue.extractMin(); if(min.nodeId == des){ printShortPath(min); return; } List<GEdge> edges = min.edges; for(GEdge edge:edges){ GNode ed = edge.des; if(min.dis+edge.weight < ed.dis){ ed.dis = min.dis+edge.weight; queue.decreaseKey(ed); ed.parent = min; } } } } private void printShortPath(GNode node){ if(node.parent!=null){ printShortPath(node.parent); System.out.println(node.nodeId); } } public static void main(String[] args) { Dijkstra dij = new Dijkstra(); dij.addNode(new int[]{1,2,3,4,5}); dij.addUnDirectedEdge(1, 2, 1); dij.addUnDirectedEdge(1, 3, 1); dij.addUnDirectedEdge(2, 4, 2); dij.addUnDirectedEdge(3, 4, 3); dij.addUnDirectedEdge(4, 5, 3); dij.shortPath(1, 5); } }
BellFord-man 算法:
对边进行迭代的算法,需要迭代|V|-1 次
复杂度为 O(EV)
package graphic; import java.util.ArrayList; import java.util.List; public class BellmanFord { static int NODE_NUM =0 ; GNode[] nodes ; List<GEdge> edges = new ArrayList<GEdge>(); public void addNode(int[] ids){ NODE_NUM = ids.length; nodes = new GNode[NODE_NUM+1]; for(Integer id:ids){ nodes[id] = new GNode(id); } } public void addEdge(int src,int des,int weight){ GEdge edge = new GEdge(nodes[src],nodes[des],weight); edges.add(edge); } public boolean shortestPath(int src){ nodes[src].dis = 0; for(int i=1;i<NODE_NUM;i++){ for(GEdge edge:edges){ GNode start = edge.src; GNode end = edge.des; if(start.dis+edge.weight < end.dis){ end.dis = start.dis+edge.weight; end.parent = start; } } } for(GEdge edge:edges){ GNode start = edge.src; GNode end = edge.des; if(start.dis+edge.weight < end.dis){ return false; } } return true; } public static void main(String[] args) { BellmanFord dij = new BellmanFord(); dij.addNode(new int[]{1,2,3,4,5}); dij.addEdge(1, 2, 1); dij.addEdge(1, 3, 1); dij.addEdge(2, 4, 2); dij.addEdge(3, 4, 3); dij.addEdge(4, 5, 3); dij.shortestPath(1); for(int i=1;i<=NODE_NUM;i++){ System.out.println(dij.nodes[i].dis); } } }
边和点的数据结构:
package graphic; public class GEdge { GNode src; GNode des; int weight = 0 ; public GEdge(GNode src,GNode des,int weight) { this.src = src; this.des = des; this.weight = weight; } } package graphic; import java.util.ArrayList; import java.util.List; public class GNode implements Comparable<GNode>{ int nodeId; GNode parent = null; int dis = Integer.MAX_VALUE; int discoverTime =0; int finishTime =0; Color color = Color.White; List<GEdge> edges = new ArrayList<GEdge>(); public GNode(Integer id) { this.nodeId = id; } public int getNodeId() { return nodeId; } public void setNodeId(int nodeId) { this.nodeId = nodeId; } public GNode getParent() { return parent; } public void setParent(GNode parent) { this.parent = parent; } public int getDis() { return dis; } public void setDis(int dis) { this.dis = dis; } public int getDiscoverTime() { return discoverTime; } public void setDiscoverTime(int discoverTime) { this.discoverTime = discoverTime; } public int getFinishTime() { return finishTime; } public void setFinishTime(int finishTime) { this.finishTime = finishTime; } public Color getColor() { return color; } public void setColor(Color color) { this.color = color; } public List<GEdge> getEdges() { return edges; } public void setEdges(List<GEdge> edges) { this.edges = edges; } @Override public int compareTo(GNode arg0) { if(this.dis > arg0.dis){ return 1; }else if(this.dis == arg0.dis)return 0; return -1; } @Override public boolean equals(Object obj) { return this.nodeId == ((GNode)obj).nodeId; } @Override public String toString() { return "id: "+nodeId+"\tdis: "+dis; } }
相关推荐
最短路径算法Dijkstra是图论中的一个经典算法,由荷兰计算机科学家艾兹格·迪科斯彻在1956年提出。该算法主要用于寻找带权重的有向或无向图中,从一个特定顶点到其他所有顶点的最短路径。Dijkstra算法的核心思想是...
2. Bellman-Ford算法:Bellman-Ford算法可以处理带有负权边的图,同样能找出单源最短路径。其时间复杂度为O(n*|E|),适用于稀疏图。若要找到k-最短路径,可以在找到第一条最短路径后,通过回溯和重新计算剩余边的...
Dijkstra算法是一种常用的寻找单源最短路径的算法,它依赖于贪心策略,每次选取当前未标记顶点中距离源点最近的一个进行扩展。然而,Dijkstra算法有一个限制,即它不适用于存在负权值边的图。因为负权值边可能导致更...
这个问题有几种著名的解决方案,如Dijkstra算法和Bellman-Ford算法。 1. **Dijkstra算法**:由Edsger Dijkstra于1956年提出,是最常用的解决单源最短路径的方法。该算法基于贪心策略,每次选取当前未访问节点中与源...
Bellman-Ford 算法和 Dijkstra 算法同为解决单源最短路径的算法。对于带权有向图 G = (V, E),Dijkstra 算法要求图 G 中边的权值均为非负,而 Bellman-Ford 算法能适应一般的情况(即存在负权边的情况)。一个实现的...
Dijkstra算法是解决单源最短路径问题的一种常用方法,它具有很高的效率和精度。但是,在实际应用中,需要根据具体情况选择合适的算法和数据结构,以确保算法的稳定性和高效性。 知识点: 1. Dijkstra算法:一种...
图论算法库 C++ 语言实现 代码内容 图论算法库,包括以下算法: 单源最短路径 Dijkstra 算法 单源最短路径 Bellman-Ford 算法 最小生成树 Prim 算法 每对节点间最短路径 Flod-Warshall 算法
在计算机科学领域,尤其是图论和算法设计中,求解单源最短路径问题是一项基本任务。这通常涉及在一个加权图中找到从一个特定顶点(源节点)到所有其他顶点的最短路径。这个问题在路由、物流、网络优化等实际场景中有...
**Bellman-Ford算法**是解决带负权边的单源最短路径问题的一种经典算法。它通过松弛操作逐步更新所有边的路径长度,总共迭代V-1次(V是图的顶点数),确保找到最短路径。每次迭代,算法检查是否存在一条边可以减少...
本篇文章将深入探讨单源最短路径算法,并通过VC++环境下的C++代码实现来帮助理解。 首先,我们要了解几种常见的单源最短路径算法: 1. **Dijkstra算法**:由荷兰计算机科学家艾兹格·迪科斯彻于1956年提出,适用于...
解决这类问题的常用算法有Dijkstra算法、Bellman-Ford算法等,其中Dijkstra算法适用于所有边的权重均为非负的情况。 #### Dijkstra算法原理 Dijkstra算法是由荷兰计算机科学家Edsger W. Dijkstra于1956年提出的一...
2. Bellman-Ford算法:Bellman-Ford算法可以处理包含负权重边的图,通过松弛操作逐步更新所有节点到源节点的最短路径。它执行V-1次迭代(V为图中节点数量),确保找到所有可能的最短路径。尽管时间复杂度较高,为O(V...
本文主要探讨了两种解决单源最短路径问题的算法:Floyd算法和Bellman-Ford算法。这两种算法在处理负权重时具有不同的特性。Dijkstra算法,虽然在正权重图中非常有效,但无法处理负权重边。相比之下,Bellman-Ford...
Java版的贪心算法实现单源最短路径,通常是基于Dijkstra算法或Bellman-Ford算法。这两种算法各有其特点和适用场景。 Dijkstra算法是一种效率较高的算法,适用于边的权重非负的情况。它通过维护一个优先队列,每次...
本文主要研究了最短路径算法在计算机网络路由选择中的应用,讨论了Dijkstra算法和Bellman-Ford算法在计算机网络中的实际应用,并对不同算法的性能和效率进行了评价。 一、计算机网络路由选择的重要性 计算机网络是...
Dijkstra算法是最常用的求解单源最短路径的贪心算法之一,由荷兰计算机科学家艾兹格·迪科斯彻于1956年提出。这个算法适用于加权有向图或无向图,其基本思想是每次扩展最短路径树,将当前未访问且与已访问节点距离...
Dijkstra算法是由荷兰计算机科学家Edsger Dijkstra于1956年提出的,它是一种解决单源最短路径问题的有效方法。在MATLAB中,我们可以利用Dijkstra算法来找到图中所有点之间的最短路径。 Dijkstra算法的基本思想是...
1. **Dijkstra算法**:Dijkstra算法是最常用的单源最短路径算法,适用于边权非负的情况。它通过维护一个优先队列(通常是二叉堆)来不断更新最短路径。算法的基本思想是从源节点开始,逐步扩展最短路径,直到遍历到...
常见的算法实现有Dijkstra算法和Bellman-Ford算法。 - 在分布式环境中,可以通过MapReduce框架来并行化SSSP算法,提高处理大规模图数据的能力。 2. **MapReduce框架**: - MapReduce是一种编程模型,用于处理大...
常见的单源最短路径算法有Dijkstra算法、Bellman-Ford算法和Floyd-Warshall算法。Dijkstra算法适用于非负权重的图,以贪心策略逐步扩展最短路径树;而Bellman-Ford算法则能处理包含负权重边的图,通过松弛操作逐步...