github.com/LdDl/ch@v1.7.8/vanilla_dijkstra.go (about)

     1  package ch
     2  
     3  import (
     4  	"container/heap"
     5  	"log"
     6  )
     7  
     8  // VanillaShortestPath Computes and returns shortest path and it's cost (vanilla Dijkstra's algorithm)
     9  //
    10  // If there are some errors then function returns '-1.0' as cost and nil as shortest path
    11  //
    12  // source User's definied ID of source vertex
    13  // target User's definied ID of target vertex
    14  //
    15  // https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
    16  func (graph *Graph) VanillaShortestPath(source, target int64) (float64, []int64) {
    17  
    18  	if source == target {
    19  		return 0, []int64{source}
    20  	}
    21  	var ok bool
    22  
    23  	if source, ok = graph.mapping[source]; !ok {
    24  		log.Println("No such source")
    25  		return -1.0, nil
    26  	}
    27  	if target, ok = graph.mapping[target]; !ok {
    28  		log.Println("No such target")
    29  		return -1.0, nil
    30  	}
    31  
    32  	// create vertex set Q
    33  	Q := &minHeap{}
    34  
    35  	// dist[source] ← 0
    36  	distance := make(map[int64]float64, len(graph.Vertices))
    37  	distance[source] = 0
    38  
    39  	// prev[v] ← UNDEFINED
    40  	prev := make(map[int64]int64, len(graph.Vertices))
    41  	// for each vertex v in Graph:
    42  	for i := range graph.Vertices {
    43  		// if v ≠ source:
    44  		if graph.Vertices[i].vertexNum != source {
    45  			// dist[v] = INFINITY
    46  			distance[graph.Vertices[i].vertexNum] = Infinity
    47  		}
    48  		// prev[v] ← UNDEFINED
    49  		// nothing here
    50  	}
    51  	Q.add_with_priority(graph.Vertices[source].vertexNum, distance[graph.Vertices[source].vertexNum])
    52  	heap.Init(Q)
    53  	// while Q is not empty:
    54  	for Q.Len() != 0 {
    55  		// u ← Q.extract_min()
    56  		u := heap.Pop(Q).(*minHeapVertex)
    57  
    58  		// if u == target:
    59  		if u.id == target {
    60  			// break
    61  			break
    62  		}
    63  
    64  		vertexList := graph.Vertices[u.id].outIncidentEdges
    65  
    66  		// for each neighbor v of u:
    67  		for v := range vertexList {
    68  			neighbor := vertexList[v].vertexID
    69  			if v1, ok1 := graph.shortcuts[u.id]; ok1 {
    70  				if _, ok2 := v1[neighbor]; ok2 {
    71  					// Ignore shortcut
    72  					continue
    73  				}
    74  			}
    75  			cost := vertexList[v].weight
    76  			// alt ← dist[u] + length(u, v)
    77  			alt := distance[u.id] + cost
    78  			// if alt < dist[v]
    79  			if distance[neighbor] > alt {
    80  				// dist[v] ← alt
    81  				distance[neighbor] = alt
    82  				// prev[v] ← u
    83  				prev[neighbor] = u.id
    84  				// Q.decrease_priority(v, alt)
    85  				// Q.decrease_priority(v, alt)
    86  				Q.add_with_priority(neighbor, alt)
    87  			}
    88  		}
    89  		// heap.Init(Q)
    90  	}
    91  
    92  	if distance[target] == Infinity {
    93  		return -1, []int64{}
    94  	}
    95  	// path = []
    96  	var path []int64
    97  	// u = target
    98  	u := target
    99  
   100  	// while prev[u] is defined:
   101  	for {
   102  		if _, ok := prev[u]; !ok {
   103  			break
   104  		}
   105  		// path.push_front(u)
   106  		temp := make([]int64, len(path)+1)
   107  		temp[0] = u
   108  		copy(temp[1:], path)
   109  		path = temp
   110  
   111  		// u = prev[u]
   112  		u = prev[u]
   113  	}
   114  
   115  	temp := make([]int64, len(path)+1)
   116  	temp[0] = source
   117  	copy(temp[1:], path)
   118  	path = temp
   119  
   120  	usersLabelsPath := make([]int64, len(path))
   121  	for e := 0; e < len(usersLabelsPath); e++ {
   122  		usersLabelsPath[e] = graph.Vertices[path[e]].Label
   123  	}
   124  
   125  	// return path, prev
   126  	return distance[target], usersLabelsPath
   127  }