dijkstra_s_algorithm.sf 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. #!/usr/bin/ruby
  2. #
  3. ## https://rosettacode.org/wiki/Dijkstra%27s_algorithm
  4. #
  5. class Graph(*args) {
  6. struct Node {
  7. String name,
  8. Array edges = [],
  9. Number dist = Inf,
  10. Node prev = nil,
  11. Bool visited = false,
  12. }
  13. struct Edge {
  14. Number weight,
  15. Node vertex,
  16. }
  17. has g = Hash()
  18. method init {
  19. args.each { |a|
  20. self.add_edge(a...)
  21. }
  22. }
  23. method get(name) {
  24. g{name}
  25. }
  26. method add_edge(a, b, weight) {
  27. g{a} ||= Node(name: a)
  28. g{b} ||= Node(name: b)
  29. g{a}.edges << Edge(weight, g{b})
  30. }
  31. method push_priority(a, v) {
  32. var i = 0
  33. var j = a.end
  34. while (i <= j) {
  35. var k = ((i + j) // 2)
  36. if (a[k].dist >= v.dist) {
  37. j = k-1
  38. }
  39. else {
  40. i = k+1
  41. }
  42. }
  43. a.insert(i, v)
  44. }
  45. method dijkstra(a, b) {
  46. g{a}.dist = 0
  47. var h = []
  48. self.push_priority(h, g{a})
  49. while (!h.is_empty) {
  50. var v = h.shift
  51. break if (v.name == b)
  52. v.visited = true
  53. v.edges.each { |e|
  54. var u = e.vertex
  55. if (!u.visited && (v.dist+e.weight <= u.dist)) {
  56. u.prev = v
  57. u.dist = (v.dist + e.weight)
  58. self.push_priority(h, u)
  59. }
  60. }
  61. }
  62. }
  63. }
  64. var g = Graph(
  65. ["a", "b", 7],
  66. ["a", "c", 9],
  67. ["a", "f", 14],
  68. ["b", "c", 10],
  69. ["b", "d", 15],
  70. ["c", "d", 11],
  71. ["c", "f", 2],
  72. ["d", "e", 6],
  73. ["e", "f", 9],
  74. )
  75. g.dijkstra('a', 'e')
  76. var v = g.get('e')
  77. var a = []
  78. while (v != nil) {
  79. a << v.name
  80. v = v.prev
  81. }
  82. var path = a.reverse.join
  83. say "#{g.get('e').dist} #{path}"
  84. assert_eq(g.get('e').dist, 26)
  85. assert_eq(path, "acde")