Dijkstra in R

Gepostet: , Zuletzt aktualisiert:

dijkstra <- function(graph, start){
  #' Implementation of dijkstra using adjacency matrix.
  #' This returns an array containing the length of the shortest path from the start node to each other node.
  #' It is only guaranteed to return correct results if there are no negative edges in the graph. Positive cycles are fine.
  #' This has a runtime of O(|V|^2) (|V| = number of Nodes), for a faster implementation see @see ../fast/Dijkstra.java (using adjacency lists)
  #' @param graph an adjacency-matrix-representation of the graph where (x,y) is the weight of the edge or 0 if there is no edge.
  #' @param start the node to start from.
  #' @return an array containing the shortest distances from the given start node to each other node
  
  
  # This contains the distances from the start node to all other nodes
  distances = rep(Inf, nrow(graph))
  
  # This contains whether a node was already visited
  visited = rep(FALSE, nrow(graph))
  
  # The distance from the start node to itself is of course 0
  distances[start] = 0
  
  # While there are nodes left to visit...
  repeat{
    
    # ... find the node with the currently shortest distance from the start node...
    shortest_distance = Inf
    shortest_index = -1
    for(i in seq_along(distances)) {
      # ... by going through all nodes that haven't been visited yet
      if(distances[i] < shortest_distance && !visited[i]){
        shortest_distance = distances[i]
        shortest_index = i
      }
    }
    
    cat("Visiting node ", shortest_index, " with current distance ", shortest_distance, "\n")
    
    if(shortest_index == -1){
      # There was no node not yet visited --> We are done
      return (distances)
    }
    # ...then, for all neighboring nodes that haven't been visited yet....
    for(i in seq_along(graph[shortest_index,])) {
      # ...if the path over this edge is shorter...
      if(graph[shortest_index,i] != 0 && distances[i] > distances[shortest_index] + graph[shortest_index,i]){
        # ...Save this path as new shortest path.
        distances[i] = distances[shortest_index] + graph[shortest_index,i]
        cat("Updating distance of node ", i, " to ", distances[i], "\n")
      }
      # Lastly, note that we are finished with this node.
      visited[shortest_index] = TRUE
      cat("Visited nodes: ", visited, "\n")
      cat("Currently lowest distances: ", distances, "\n")
    }
  }
}

Über den Algorithmus und die Programmiersprache in diesem Snippet:

Dijkstra's Algorithmus

Der Dijkstra-Algorithmus ist ein Algorithmus, der verwendet wird, um das Problem des kürzesten Pfades in einem Diagramm zu lösen. Dies bedeutet, dass der Dijkstra-Algorithmus bei einer Anzahl von Knoten und den Kanten zwischen ihnen sowie der “Länge” der Kanten (als “Gewicht” bezeichnet) den kürzesten Weg vom angegebenen Startknoten zu allen anderen Knoten findet.

Beschreibung des Algorithmus

Das Grundprinzip des Dijkstra-Algorithmus besteht darin, den Knoten mit dem derzeit kleinsten Abstand zur Quelle iterativ zu betrachten und alle noch nicht besuchten Nachbarn zu aktualisieren, wenn der Pfad zu ihm über den aktuellen Knoten kürzer ist. Im Einzelnen führt dies zu den folgenden Schritten:

  1. Initialisieren Sie den Abstand zum Startknoten als 0 und den Abstand zu allen anderen Knoten als unendlich
  2. Setzen Sie alle Knoten auf “nicht besucht”.
  3. Während wir nicht alle Knoten besucht haben:

    1. Suchen Sie den Knoten mit der aktuell kürzesten Entfernung von der Quelle (beim ersten Durchgang ist dies der Quellknoten selbst).
    2. Überprüfen Sie für alle Knoten daneben, die wir noch nicht besucht haben, ob die derzeit kleinste Entfernung zu diesem Nachbarn größer ist, als wenn wir über den aktuellen Knoten gehen würden
    3. Wenn dies der Fall ist, aktualisieren Sie die kleinste Entfernung dieses Nachbarn auf die Entfernung von der Quelle zum aktuellen Knoten plus die Entfernung vom aktuellen Knoten zu diesem Nachbarn

Am Ende enthält das Array, mit dem wir die aktuell kürzeste Entfernung von der Quelle zu allen anderen Knoten verfolgt haben, die (endgültigen) kürzesten Entfernungen.

Beispiel des Algorithmus

Betrachten Sie das folgende Diagramm: Grafik für den Dijkstra-Algorithmus für kürzeste Wege

Die Schritte, die der Algorithmus in diesem Diagramm ausführt, wenn der Knoten 0 als Startpunkt angegeben wird, sind:

  1. Besuche Knoten 0
  2. Aktualisieren der Entfernung von Knoten 1 bis 3
  3. Aktualisieren des Abstands von Knoten 2 zu 1
  4. Besuchte Knoten: 0
  5. Derzeit niedrigste Entfernungen: [0, 3, 1, unendlich, unendlich, unendlich]
  6. Besuch von Knoten 1 mit der aktuellen Entfernung 1

    • Aktualisieren der Entfernung von Knoten 3 bis 5
    • Besuchte Knoten: 0, 2
    • Derzeit niedrigste Entfernungen: [0, 3, 1, 5, unendlich, unendlich]
  7. Besuch von Knoten 3 mit der aktuellen Entfernung 3

    • Aktualisieren der Entfernung von Knoten 4 bis 4
    • Besuchte Knoten: 0, 1, 2
    • Derzeit niedrigste Entfernungen: [0, 3, 1, 5, 4, unendlich]
  8. Besuche Knoten 4 mit der aktuellen Entfernung 4

    • Aktualisieren der Entfernung von Knoten 5 bis 5
    • Besuchte Knoten: 0, 1, 2, 4
    • Derzeit niedrigste Entfernungen: [0, 3, 1, 5, 4, 5]
  9. Besuche Knoten 5 mit aktueller Entfernung 5

    • Keine zu aktualisierenden Entfernungen
    • Besuchte Knoten: 0, 1, 2, 3, 4
    • Derzeit niedrigste Entfernungen: [0, 3, 1, 5, 4, 5]
  10. Besuch des Knotens 5 mit der aktuellen Entfernung 5

    • Keine zu aktualisierenden Entfernungen
    • Besuchte Knoten: 0, 1, 2, 3, 4, 5

Alle besuchten Knoten Letzte niedrigste Abstände: [0, 3, 1, 5, 4, 5]

Laufzeit des Algorithmus

Die Laufzeitkomplexität von Dijkstra hängt davon ab, wie es implementiert wird. Wenn ein Min-Heap verwendet wird, um den nächsten zu besuchenden Knoten zu bestimmen, und die Adjazenz unter Verwendung von Adjazenzlisten implementiert wird, ist die Laufzeit O(| E | + | V | log | V|) (|V| = Nummer Anzahl der Knoten, |E| = Anzahl der Kanten). Wenn wir einfach alle Entfernungen durchsuchen, um den Knoten mit der niedrigsten Entfernung in jedem Schritt zu finden, und mithilfe einer Matrix nachsehen, ob zwei Knoten benachbart sind, steigt die Laufzeitkomplexität auf O(| V | ^ 2).

Speicherkomplexität des Algorithmus

Die Speicherkomplexität von Dijkstra hängt auch davon ab, wie es implementiert ist, und entspricht der Laufzeitkomplexität.

R

The R Logo

R ist eine interpretierte Sprache, die erstmals 1993 veröffentlicht wurde und in den letzten Jahren erheblich an Popularität gewonnen hat. Es wird hauptsächlich für Data Mining und -science sowie für Statistiken verwendet und ist eine beliebte Sprache in Disziplinen außerhalb der Informatik, die von Biologie bis Physik reichen. R ist dynamisch typisiert und verfügt über eine der vielfältigsten Bibliotheken für Statistik, maschinelles Lernen, Data Mining usw.

<! - Ende des Auszugs ->

Anreise zu “Hello World” in R.

Das Wichtigste zuerst - hier erfahren Sie, wie Sie Ihre erste Codezeile in R ausführen können.

  1. Laden Sie die neueste Version von R von r-project.org herunter und installieren Sie sie. Sie können auch eine frühere Version herunterladen, wenn Ihr Anwendungsfall dies erfordert.
  2. Öffnen Sie ein Terminal, stellen Sie sicher, dass der Befehl R funktioniert und dass der Befehl, den Sie verwenden werden, sich auf die Version bezieht, die Sie gerade installiert haben, indem SieR --version ausführen. Wenn der Fehler “Befehl nicht gefunden” (oder ähnlich) angezeigt wird, starten Sie die Befehlszeile und, falls dies nicht hilft, Ihren Computer neu. Wenn das Problem weiterhin besteht, finden Sie hier einige hilfreiche Fragen zu StackOverflow für Windows, Mac und Linux .
  3. Sobald dies funktioniert, können Sie das folgende Snippet ausführen: print (" Hello World "). Sie haben zwei Möglichkeiten, dies auszuführen: 3.1 Führen Sie “R” in der Befehlszeile aus, fügen Sie einfach das Code-Snippet ein und drücken Sie die Eingabetaste (Drücken Sie “STRG + D” und geben Sie “n” gefolgt von der Eingabetaste ein, um das Menü zu verlassen). 3.2 Speichern Sie das Snippet in einer Datei und nennen Sie es etwas, das mit “.R” endet, z. hello_world.R und führen SieRscript hello_world.R aus. Tipp: Verwenden Sie den Befehl ls (dir in Windows), um herauszufinden, welche Dateien sich in dem Ordner befinden, in dem sich Ihre Befehlszeile gerade befindet.

Das ist es! Beachten Sie, dass das Drucken von etwas auf die Konsole nur eine einzige Zeile in R ist - diese niedrige Eintrittsbarriere und das Fehlen des erforderlichen Boilerplate-Codes machen einen großen Teil der Attraktivität von R aus.

Grundlagen in R.

Um in R implementierte Algorithmen und Technologien zu verstehen, muss man zunächst verstehen, wie grundlegende Programmierkonzepte in dieser bestimmten Sprache aussehen.

Variablen und Arithmetik

Variablen in R sind wirklich einfach. Sie müssen weder einen Datentyp deklarieren noch deklarieren, dass Sie eine Variable definieren. R weiß das implizit. R ist auch in der Lage, Objekte und ihre Eigenschaften auf verschiedene Arten einfach zu definieren.

some_value = 10
my_object <- list(my_value = 4)
attr(my_object, 'other_value') <- 3

print((some_value + my_object$my_value + attr(my_object, 'other_value'))) # Prints 17

Arrays

Das Arbeiten mit Arrays ist in R ähnlich einfach:

# Create 2 vectors of length 3
vector1 <- c(1,2,3)
vector2 <- c(4,5,6)

# Create names for rows and columns (optional)
column.names <- c("column_1","column_2","column_3")
row.names <- c("row_1","row_2")

# Concatenate the vectors (as rows) to form an array, providing dimensions and row/column names
result <- array(c(vector1,vector2), dim = c(2,3), dimnames = list(row.names, column.names))

print(result)
# Prints:
#       column_1 column_2 column_3
# row_1        1        3        5
# row_2        2        4        6

Wie diejenigen unter Ihnen, die mit anderen Programmiersprachen wie Java vertraut sind, möglicherweise bereits bemerkt haben, handelt es sich nicht um native Arrays, sondern um Listen, die wie Arrays gekleidet sind. Dies bedeutet, dass Arrays in R erheblich langsamer sind als in Programmiersprachen niedrigerer Ebene. Dies ist ein Kompromiss, den R zugunsten der Einfachheit eingeht. Es gibt jedoch Pakete, die echte Arrays implementieren, die erheblich schneller sind.

Bedingungen

Wie die meisten Programmiersprachen kann R “if-else” -Anweisungen ausführen:

value = 1
if(value==1){
   print("Value is 1")
} else if(value==2){
     print("Value is 2")
} else {
     print("Value is something else")
}

R kann auch switch-Anweisungen ausführen, obwohl sie im Gegensatz zu anderen Sprachen wie Java als Funktion implementiert sind:

x <- switch(
   1,
   "Value is 1",
   "Value is 2",
   "Value is 3"
)

print(x)

Beachten Sie, dass diese Funktion ziemlich nutzlos ist, es jedoch andere Funktionen für komplexere Anwendungsfälle gibt.

Schleifen

R unterstützt sowohl for- als auch while-Schleifen sowie break- und next-Anweisungen (vergleichbar mit continue in anderen Sprachen). Zusätzlich unterstützt R “Wiederholungsschleifen”, die mit “while (true)” - Schleifen in anderen Sprachen vergleichbar sind, aber den Code ein wenig vereinfachen.

value <- 0
repeat {
  value <- value + 1
  if(value > 10) {
    break
  }
}
print(value)

value <- 0
while (value <= 10) {
  value = value + 1
}
print(value)

value <- c("Hello","World","!")
for ( i in value) {
  print(i)
}

for(i in 1:10){
  print(i)
}

Funktionen

Funktionen in R sind einfach zu definieren und erfordern zum Guten oder Schlechten keine Angabe von Rückgabe- oder Argumenttypen. Optional kann ein Standardwert für Argumente angegeben werden:

my_func <- function (
  a = "World"
) {
  print(a)
  return("!")
}

my_func("Hello")
print(my_func())

(Dies druckt “Hallo”, “Welt” und dann ”!“)

Syntax

R erfordert die Verwendung von geschweiften Klammern ({}), um Codeblöcke in Bedingungen, Schleifen, Funktionen usw.; Dies kann zwar zu lästigen Syntaxfehlern führen, bedeutet jedoch auch, dass die Verwendung von Leerzeichen für die bevorzugte Formatierung (z. B. Einrücken von Codeteilen) den Code nicht beeinflusst.

Fortgeschrittenes Wissen in R

Für weitere Informationen hat R einen großartigen Artikel Wikipedia. Die offizielle Website ist r-project.org.