`
sunlujing
  • 浏览: 179698 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

单源最短路径算法 Dijkstra和Bellman-Ford

阅读更多

常用的单源最短路径算法一共有两个,一个是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;
				
	}
}

 

 

1
2
分享到:
评论

相关推荐

    最短路径算法Dijkstra源代码

    最短路径算法Dijkstra是图论中的一个经典算法,由荷兰计算机科学家艾兹格·迪科斯彻在1956年提出。该算法主要用于寻找带权重的有向或无向图中,从一个特定顶点到其他所有顶点的最短路径。Dijkstra算法的核心思想是...

    最短路径算法实现 k-shortest-paths

    2. Bellman-Ford算法:Bellman-Ford算法可以处理带有负权边的图,同样能找出单源最短路径。其时间复杂度为O(n*|E|),适用于稀疏图。若要找到k-最短路径,可以在找到第一条最短路径后,通过回溯和重新计算剩余边的...

    最短路径问题-Bellman-Ford算法.pdf

    Dijkstra算法是一种常用的寻找单源最短路径的算法,它依赖于贪心策略,每次选取当前未标记顶点中距离源点最近的一个进行扩展。然而,Dijkstra算法有一个限制,即它不适用于存在负权值边的图。因为负权值边可能导致更...

    求单源最短路径(算法分析中)c++

    这个问题有几种著名的解决方案,如Dijkstra算法和Bellman-Ford算法。 1. **Dijkstra算法**:由Edsger Dijkstra于1956年提出,是最常用的解决单源最短路径的方法。该算法基于贪心策略,每次选取当前未访问节点中与源...

    091-Bellman-Ford.cs

    Bellman-Ford 算法和 Dijkstra 算法同为解决单源最短路径的算法。对于带权有向图 G = (V, E),Dijkstra 算法要求图 G 中边的权值均为非负,而 Bellman-Ford 算法能适应一般的情况(即存在负权边的情况)。一个实现的...

    单源最短路径dijkstra模板

    Dijkstra算法是解决单源最短路径问题的一种常用方法,它具有很高的效率和精度。但是,在实际应用中,需要根据具体情况选择合适的算法和数据结构,以确保算法的稳定性和高效性。 知识点: 1. Dijkstra算法:一种...

    图论算法库 C++ 语言实现 代码内容 图论算法库,包括以下算法: 单源最短路径 Dijkstra 算法 单源最短路径 Bell

    图论算法库 C++ 语言实现 代码内容 图论算法库,包括以下算法: 单源最短路径 Dijkstra 算法 单源最短路径 Bellman-Ford 算法 最小生成树 Prim 算法 每对节点间最短路径 Flod-Warshall 算法

    最短路课件 求单源最短路径

    在计算机科学领域,尤其是图论和算法设计中,求解单源最短路径问题是一项基本任务。这通常涉及在一个加权图中找到从一个特定顶点(源节点)到所有其他顶点的最短路径。这个问题在路由、物流、网络优化等实际场景中有...

    单源最短路径算法、SingleSourceDemo.rar

    **Bellman-Ford算法**是解决带负权边的单源最短路径问题的一种经典算法。它通过松弛操作逐步更新所有边的路径长度,总共迭代V-1次(V是图的顶点数),确保找到最短路径。每次迭代,算法检查是否存在一条边可以减少...

    单源最短路径(算法 代码)

    本篇文章将深入探讨单源最短路径算法,并通过VC++环境下的C++代码实现来帮助理解。 首先,我们要了解几种常见的单源最短路径算法: 1. **Dijkstra算法**:由荷兰计算机科学家艾兹格·迪科斯彻于1956年提出,适用于...

    单源最短路径 直接copy 运行即可,里面有测试结果

    解决这类问题的常用算法有Dijkstra算法、Bellman-Ford算法等,其中Dijkstra算法适用于所有边的权重均为非负的情况。 #### Dijkstra算法原理 Dijkstra算法是由荷兰计算机科学家Edsger W. Dijkstra于1956年提出的一...

    最短路径算法c# 最短路径算法

    2. Bellman-Ford算法:Bellman-Ford算法可以处理包含负权重边的图,通过松弛操作逐步更新所有节点到源节点的最短路径。它执行V-1次迭代(V为图中节点数量),确保找到所有可能的最短路径。尽管时间复杂度较高,为O(V...

    单源最短路径算法设计与分析期终论文

    本文主要探讨了两种解决单源最短路径问题的算法:Floyd算法和Bellman-Ford算法。这两种算法在处理负权重时具有不同的特性。Dijkstra算法,虽然在正权重图中非常有效,但无法处理负权重边。相比之下,Bellman-Ford...

    单源最短路径

    Java版的贪心算法实现单源最短路径,通常是基于Dijkstra算法或Bellman-Ford算法。这两种算法各有其特点和适用场景。 Dijkstra算法是一种效率较高的算法,适用于边的权重非负的情况。它通过维护一个优先队列,每次...

    最短路径算法在计算机网络路由选择中的应用研究.pdf

    本文主要研究了最短路径算法在计算机网络路由选择中的应用,讨论了Dijkstra算法和Bellman-Ford算法在计算机网络中的实际应用,并对不同算法的性能和效率进行了评价。 一、计算机网络路由选择的重要性 计算机网络是...

    单源最短路径vc源码(贪心算法)

    Dijkstra算法是最常用的求解单源最短路径的贪心算法之一,由荷兰计算机科学家艾兹格·迪科斯彻于1956年提出。这个算法适用于加权有向图或无向图,其基本思想是每次扩展最短路径树,将当前未访问且与已访问节点距离...

    matlab 最短路径算法 dijkstra

    Dijkstra算法是由荷兰计算机科学家Edsger Dijkstra于1956年提出的,它是一种解决单源最短路径问题的有效方法。在MATLAB中,我们可以利用Dijkstra算法来找到图中所有点之间的最短路径。 Dijkstra算法的基本思想是...

    zuiduanlujing.rar_单源最短路径

    1. **Dijkstra算法**:Dijkstra算法是最常用的单源最短路径算法,适用于边权非负的情况。它通过维护一个优先队列(通常是二叉堆)来不断更新最短路径。算法的基本思想是从源节点开始,逐步扩展最短路径,直到遍历到...

    单源最短路径算法(MapReduce)源代码

    常见的算法实现有Dijkstra算法和Bellman-Ford算法。 - 在分布式环境中,可以通过MapReduce框架来并行化SSSP算法,提高处理大规模图数据的能力。 2. **MapReduce框架**: - MapReduce是一种编程模型,用于处理大...

    单源最短路径_最大团问题_

    常见的单源最短路径算法有Dijkstra算法、Bellman-Ford算法和Floyd-Warshall算法。Dijkstra算法适用于非负权重的图,以贪心策略逐步扩展最短路径树;而Bellman-Ford算法则能处理包含负权重边的图,通过松弛操作逐步...

Global site tag (gtag.js) - Google Analytics