📜  Dijkstra 算法的有向图中的最短路径

📅  最后修改于: 2021-10-25 03:35:32             🧑  作者: Mango

给定一个有向图和图中的一个源顶点,任务是在给定的图中找到从源到目标顶点的最短距离和路径,其中边被加权(非负)并且从父顶点指向源顶点。

方法:

  • 标记所有未访问的顶点。创建一组所有未访问的顶点。
  • 将零距离值分配给源顶点,将无穷远距离值分配给所有其他顶点。
  • 将源顶点设置为当前顶点
  • 对于当前顶点,考虑其所有未访问的子节点并计算它们通过当前的暂定距离。 (当前距离+对应边的权重)将新计算的距离与当前分配的值(对于某些顶点可以是无穷大)进行比较并分配较小的。
  • 在考虑当前顶点的所有未访问子节点后,将当前标记为已访问并将其从未访问集中删除。
  • 类似地,对所有顶点继续,直到所有节点都被访问。

下面是上述方法的实现:

C++
// C++ implementation to find the
// shortest path in a directed
// graph from source vertex to
// the destination vertex
 
#include 
#define infi 1000000000
using namespace std;
 
// Class of the node
class Node {
public:
    int vertexNumber;
 
    // Adjacency list that shows the
    // vertexNumber of child vertex
    // and the weight of the edge
    vector > children;
    Node(int vertexNumber)
    {
        this->vertexNumber = vertexNumber;
    }
 
    // Function to add the child for
    // the given node
    void add_child(int vNumber, int length)
    {
        pair p;
        p.first = vNumber;
        p.second = length;
        children.push_back(p);
    }
};
 
// Function to find the distance of
// the node from the given source
// vertex to the destination vertex
vector dijkstraDist(
    vector g,
    int s, vector& path)
{
    // Stores distance of each
    // vertex from source vertex
    vector dist(g.size());
 
    // Boolean array that shows
    // whether the vertex 'i'
    // is visited or not
    bool visited[g.size()];
    for (int i = 0; i < g.size(); i++) {
        visited[i] = false;
        path[i] = -1;
        dist[i] = infi;
    }
    dist[s] = 0;
    path[s] = -1;
    int current = s;
 
    // Set of vertices that has
    // a parent (one or more)
    // marked as visited
    unordered_set sett;
    while (true) {
 
        // Mark current as visited
        visited[current] = true;
        for (int i = 0;
             i < g[current]->children.size();
             i++) {
            int v = g[current]->children[i].first;
            if (visited[v])
                continue;
 
            // Inserting into the
            // visited vertex
            sett.insert(v);
            int alt
                = dist[current]
                  + g[current]->children[i].second;
 
            // Condition to check the distance
            // is correct and update it
            // if it is minimum from the previous
            // computed distance
            if (alt < dist[v]) {
                dist[v] = alt;
                path[v] = current;
            }
        }
        sett.erase(current);
        if (sett.empty())
            break;
 
        // The new current
        int minDist = infi;
        int index = 0;
 
        // Loop to update the distance
        // of the vertices of the graph
        for (int a: sett) {
            if (dist[a] < minDist) {
                minDist = dist[a];
                index = a;
            }
        }
        current = index;
    }
    return dist;
}
 
// Function to print the path
// from the source vertex to
// the destination vertex
void printPath(vector path,
               int i, int s)
{
    if (i != s) {
 
        // Condition to check if
        // there is no path between
        // the vertices
        if (path[i] == -1) {
            cout << "Path not found!!";
            return;
        }
        printPath(path, path[i], s);
        cout << path[i] << " ";
    }
}
 
// Driver Code
int main()
{
    vector v;
    int n = 4, s = 0, e = 5;
 
    // Loop to create the nodes
    for (int i = 0; i < n; i++) {
        Node* a = new Node(i);
        v.push_back(a);
    }
 
    // Creating directed
    // weighted edges
    v[0]->add_child(1, 1);
    v[0]->add_child(2, 4);
    v[1]->add_child(2, 2);
    v[1]->add_child(3, 6);
    v[2]->add_child(3, 3);
 
    vector path(v.size());
    vector dist
        = dijkstraDist(v, s, path);
 
    // Loop to print the distance of
    // every node from source vertex
    for (int i = 0; i < dist.size(); i++) {
        if (dist[i] == infi) {
            cout << i << " and " << s
                 << " are not connected"
                 << endl;
            continue;
        }
        cout << "Distance of " << i
             << "th vertex from source vertex "
             << s << " is: "
             << dist[i] << endl;
    }
    return 0;
}


Java
// Java implementation to find the
// shortest path in a directed
// graph from source vertex to
// the destination vertex
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
 
class Pair
{
    int first, second;
 
    public Pair(int first, int second)
    {
        this.first = first;
        this.second = second;
    }
}
 
class GFG{
 
static final int infi = 1000000000;
 
// Class of the node
static class Node
{
    int vertexNumber;
 
    // Adjacency list that shows the
    // vertexNumber of child vertex
    // and the weight of the edge
    List children;
 
    Node(int vertexNumber)
    {
        this.vertexNumber = vertexNumber;
        children = new ArrayList<>();
    }
 
    // Function to add the child for
    // the given node
    void add_child(int vNumber, int length)
    {
        Pair p = new Pair(vNumber, length);
        children.add(p);
    }
}
 
// Function to find the distance of
// the node from the given source
// vertex to the destination vertex
static int[] dijkstraDist(List g,
                          int s, int[] path)
{
     
    // Stores distance of each
    // vertex from source vertex
    int[] dist = new int[g.size()];
 
    // Boolean array that shows
    // whether the vertex 'i'
    // is visited or not
    boolean[] visited = new boolean[g.size()];
    for(int i = 0; i < g.size(); i++)
    {
        visited[i] = false;
        path[i] = -1;
        dist[i] = infi;
    }
    dist[s] = 0;
    path[s] = -1;
    int current = s;
 
    // Set of vertices that has
    // a parent (one or more)
    // marked as visited
    Set sett = new HashSet<>();
    while (true)
    {
         
        // Mark current as visited
        visited[current] = true;
        for(int i = 0;
                i < g.get(current).children.size();
                i++)
        {
            int v = g.get(current).children.get(i).first;
             
            if (visited[v])
                continue;
 
            // Inserting into the
            // visited vertex
            sett.add(v);
            int alt = dist[current] +
                     g.get(current).children.get(i).second;
 
            // Condition to check the distance
            // is correct and update it
            // if it is minimum from the previous
            // computed distance
            if (alt < dist[v])
            {
                dist[v] = alt;
                path[v] = current;
            }
        }
        sett.remove(current);
         
        if (sett.isEmpty())
            break;
 
        // The new current
        int minDist = infi;
        int index = 0;
 
        // Loop to update the distance
        // of the vertices of the graph
        for(int a : sett)
        {
            if (dist[a] < minDist)
            {
                minDist = dist[a];
                index = a;
            }
        }
        current = index;
    }
    return dist;
}
 
// Function to print the path
// from the source vertex to
// the destination vertex
void printPath(int[] path, int i, int s)
{
    if (i != s)
    {
         
        // Condition to check if
        // there is no path between
        // the vertices
        if (path[i] == -1)
        {
            System.out.println("Path not found!!");
            return;
        }
        printPath(path, path[i], s);
        System.out.print(path[i] + " ");
    }
}
 
// Driver Code
public static void main(String[] args)
{
    List v = new ArrayList<>();
    int n = 4, s = 0, e = 5;
 
    // Loop to create the nodes
    for(int i = 0; i < n; i++)
    {
        Node a = new Node(i);
        v.add(a);
    }
 
    // Creating directed
    // weighted edges
    v.get(0).add_child(1, 1);
    v.get(0).add_child(2, 4);
    v.get(1).add_child(2, 2);
    v.get(1).add_child(3, 6);
    v.get(2).add_child(3, 3);
 
    int[] path = new int[v.size()];
    int[] dist = dijkstraDist(v, s, path);
 
    // Loop to print the distance of
    // every node from source vertex
    for(int i = 0; i < dist.length; i++)
    {
        if (dist[i] == infi)
        {
            System.out.printf("%d and %d are not " +
                              "connected\n", i, s);
            continue;
        }
        System.out.printf("Distance of %dth vertex " +
                          "from source vertex %d is: %d\n",
                          i, s, dist[i]);
    }
}
}
 
// This code is contributed by sanjeev2552


Python3
# Python3 implementation to find the
# shortest path in a directed
# graph from source vertex to
# the destination vertex
class Pair:
    def __init__(self, first, second):
        self.first = first
        self.second = second
infi = 1000000000;
   
# Class of the node
class Node:
   
    # Adjacency list that shows the
    # vertexNumber of child vertex
    # and the weight of the edge   
    def __init__(self, vertexNumber):       
        self.vertexNumber = vertexNumber
        self.children = []
   
    # Function to add the child for
    # the given node
    def Add_child(self, vNumber, length):   
        p = Pair(vNumber, length);
        self.children.append(p);
       
# Function to find the distance of
# the node from the given source
# vertex to the destination vertex
def dijkstraDist(g, s, path):
       
    # Stores distance of each
    # vertex from source vertex
    dist = [infi for i in range(len(g))]
   
    # bool array that shows
    # whether the vertex 'i'
    # is visited or not
    visited = [False for i in range(len(g))]
     
    for i in range(len(g)):       
        path[i] = -1
    dist[s] = 0;
    path[s] = -1;
    current = s;
   
    # Set of vertices that has
    # a parent (one or more)
    # marked as visited
    sett = set()    
    while (True):
           
        # Mark current as visited
        visited[current] = True;
        for i in range(len(g[current].children)): 
            v = g[current].children[i].first;           
            if (visited[v]):
                continue;
   
            # Inserting into the
            # visited vertex
            sett.add(v);
            alt = dist[current] + g[current].children[i].second;
   
            # Condition to check the distance
            # is correct and update it
            # if it is minimum from the previous
            # computed distance
            if (alt < dist[v]):      
                dist[v] = alt;
                path[v] = current;       
        if current in sett:           
            sett.remove(current);       
        if (len(sett) == 0):
            break;
   
        # The new current
        minDist = infi;
        index = 0;
   
        # Loop to update the distance
        # of the vertices of the graph
        for a in sett:       
            if (dist[a] < minDist):          
                minDist = dist[a];
                index = a;          
        current = index;  
    return dist;
   
# Function to print the path
# from the source vertex to
# the destination vertex
def printPath(path, i, s):
    if (i != s):
           
        # Condition to check if
        # there is no path between
        # the vertices
        if (path[i] == -1):       
            print("Path not found!!");
            return;       
        printPath(path, path[i], s);
        print(path[i] + " ");
      
# Driver Code
if __name__=='__main__':
     
    v = []
    n = 4
    s = 0;
   
    # Loop to create the nodes
    for i in range(n):
        a = Node(i);
        v.append(a);
   
    # Creating directed
    # weighted edges
    v[0].Add_child(1, 1);
    v[0].Add_child(2, 4);
    v[1].Add_child(2, 2);
    v[1].Add_child(3, 6);
    v[2].Add_child(3, 3);
    path = [0 for i in range(len(v))];
    dist = dijkstraDist(v, s, path);
   
    # Loop to print the distance of
    # every node from source vertex
    for i in range(len(dist)):
        if (dist[i] == infi):
         
            print("{0} and {1} are not " +
                              "connected".format(i, s));
            continue;       
        print("Distance of {}th vertex from source vertex {} is: {}".format(
                          i, s, dist[i]));
     
    # This code is contributed by pratham76


C#
// C# implementation to find the
// shortest path in a directed
// graph from source vertex to
// the destination vertex
using System;
using System.Collections;
using System.Collections.Generic;
  
class Pair
{
    public int first, second;
  
    public Pair(int first, int second)
    {
        this.first = first;
        this.second = second;
    }
}
  
class GFG
{
  
static int infi = 1000000000;
  
// Class of the node
class Node
{
    public int vertexNumber;
  
    // Adjacency list that shows the
    // vertexNumber of child vertex
    // and the weight of the edge
    public List children;
  
    public Node(int vertexNumber)
    {
        this.vertexNumber = vertexNumber;
        children = new List();
    }
  
    // Function to Add the child for
    // the given node
    public void Add_child(int vNumber, int length)
    {
        Pair p = new Pair(vNumber, length);
        children.Add(p);
    }
}
  
// Function to find the distance of
// the node from the given source
// vertex to the destination vertex
static int[] dijkstraDist(List g,
                          int s, int[] path)
{
      
    // Stores distance of each
    // vertex from source vertex
    int[] dist = new int[g.Count];
  
    // bool array that shows
    // whether the vertex 'i'
    // is visited or not
    bool[] visited = new bool[g.Count];
    for(int i = 0; i < g.Count; i++)
    {
        visited[i] = false;
        path[i] = -1;
        dist[i] = infi;
    }
    dist[s] = 0;
    path[s] = -1;
    int current = s;
  
    // Set of vertices that has
    // a parent (one or more)
    // marked as visited
    HashSet sett = new HashSet();
     
    while (true)
    {
          
        // Mark current as visited
        visited[current] = true;
        for(int i = 0;
                i < g[current].children.Count;
                i++)
        {
            int v = g[current].children[i].first;           
            if (visited[v])
                continue;
  
            // Inserting into the
            // visited vertex
            sett.Add(v);
            int alt = dist[current] +
                     g[current].children[i].second;
  
            // Condition to check the distance
            // is correct and update it
            // if it is minimum from the previous
            // computed distance
            if (alt < dist[v])
            {
                dist[v] = alt;
                path[v] = current;
            }
        }
        sett.Remove(current);
          
        if (sett.Count == 0)
            break;
  
        // The new current
        int minDist = infi;
        int index = 0;
  
        // Loop to update the distance
        // of the vertices of the graph
        foreach(int a in sett)
        {
            if (dist[a] < minDist)
            {
                minDist = dist[a];
                index = a;
            }
        }
        current = index;
    }
    return dist;
}
  
// Function to print the path
// from the source vertex to
// the destination vertex
void printPath(int[] path, int i, int s)
{
    if (i != s)
    {
          
        // Condition to check if
        // there is no path between
        // the vertices
        if (path[i] == -1)
        {
            Console.WriteLine("Path not found!!");
            return;
        }
        printPath(path, path[i], s);
        Console.WriteLine(path[i] + " ");
    }
}
  
// Driver Code
public static void Main(string[] args)
{
    List v = new List();
    int n = 4, s = 0;
  
    // Loop to create the nodes
    for(int i = 0; i < n; i++)
    {
        Node a = new Node(i);
        v.Add(a);
    }
  
    // Creating directed
    // weighted edges
    v[0].Add_child(1, 1);
    v[0].Add_child(2, 4);
    v[1].Add_child(2, 2);
    v[1].Add_child(3, 6);
    v[2].Add_child(3, 3);
  
    int[] path = new int[v.Count];
    int[] dist = dijkstraDist(v, s, path);
  
    // Loop to print the distance of
    // every node from source vertex
    for(int i = 0; i < dist.Length; i++)
    {
        if (dist[i] == infi)
        {
            Console.Write("{0} and {1} are not " +
                              "connected\n", i, s);
            continue;
        }
        Console.Write("Distance of {0}th vertex " +
                          "from source vertex {1} is: {2}\n",
                          i, s, dist[i]);
    }
}
}
 
// This code is contributed by rutvik_56


输出:
第 0 个顶点与源顶点 0 的距离为:0
第 1 个顶点与源顶点 0 的距离为:1
第 2 个顶点与源顶点 0 的距离为:3
第 3 个顶点与源顶点 0 的距离为:6

时间复杂度: {\displaystyle \Theta ((|V|^{2})\log |V|)}
辅助空间: O(V + E)
相关文章:我们已经讨论了使用拓扑排序的有向图中的最短路径,在这篇文章中:有向无环图中的最短路径