单源最短路径算法 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;
                
    }
}

 

 

    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/sunlujing/article/details/84436737
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞