Eine Variante des Verfahrens von Floyd zur Bestimmung kürzester

Werbung
Rheinische Friedrich-Wilhelms-Universität Bonn
Institut für Informatik III
Professor Dr. Rainer Manthey
Professor Dr. Lutz Plümer
Eine Variante des Verfahrens von Floyd zur
Bestimmung kürzester Wege in einem
hierarchischen Straßennetz
Diplomarbeit von
Lasse Asbach
Bonn, im Juli 2002
i
ii
Inhalt
Inhalt......................................................................................................................................i
Abbildungsverzeichnis ........................................................................................................v
Tabellenverzeichnis ............................................................................................................vi
Kurzfassung/Abstract ...................................................................................................... vii
Vorwort............................................................................................................................. viii
1 Einleitung........................................................................................................................1
2 Kürzeste Wege in der klassischen Graphentheorie ....................................................4
2.1 Einleitung und grundlegende Definitionen ..............................................................4
2.2 Algorithmen zur Berechnung kürzester Wege .........................................................8
2.2.1Übersicht ................................................................................................................................... 8
2.2.2Im Detail: Algorithmus von Dijkstra....................................................................................... 10
2.2.3Im Detail: Algorithmus von Floyd .......................................................................................... 20
3 Kürzeste Wege in Straßennetzen................................................................................27
3.1 Einleitung und Definitionen ...................................................................................27
3.2 Modellierung eines realen Straßennetzes...............................................................28
3.2.1Granularität.............................................................................................................................. 28
3.2.2Redundanz ............................................................................................................................... 30
3.2.3Korrektheit der Modellierung.................................................................................................. 31
3.2.4Kantenkosten ........................................................................................................................... 32
3.3 Kürzeste Wege .......................................................................................................32
4 Variante der Floyd-Wege-Matrix für Straßennetze.................................................34
4.1 Die Floyd-Wege-Matrix genauer betrachtet ..........................................................34
4.2 Variante der Floyd-Wege-Matrix für Straßennetze ...............................................38
4.3 Algorithmus zur Transformierung der Floyd-Wege-Matrix ..................................41
4.4 Beispielanwendung ................................................................................................45
iii
5 Anwendung der Variante der Floyd-Wege-Matrix in einem hierarchischen
Strassennetz ..................................................................................................................51
5.1 Grundmodell...........................................................................................................51
5.1.1Idee 52
5.1.2Straßensubnetze....................................................................................................................... 53
5.1.3Algorithmus zur Ermittlung kürzester Wege........................................................................... 55
5.2 Herleitung der Straßensubnetze .............................................................................58
5.2.1Optimierungskriterien.............................................................................................................. 59
5.2.2Heuristik: Landkreise und Autobahnunternetz als Grundlage für die Subnetze ..................... 62
5.2.3Güte der Heuristik ................................................................................................................... 74
5.3 Verwendung der Variante der Floyd-Wege-Matrix ...............................................81
5.3.1Datenstrukturen ....................................................................................................................... 81
5.3.2Performanz und Komplexität................................................................................................... 83
5.3.3Mögliche praktische Anwendungen ........................................................................................ 87
6 Implementation ............................................................................................................89
6.1 Bedienung und Funktionalität des Straßennetz-Editors.........................................89
6.2 Algorithmen ...........................................................................................................91
7 Zusammenfassung........................................................................................................93
Literatur .............................................................................................................................96
Erklärung ...........................................................................................................................97
iv
Abbildungsverzeichnis
Abb. 1
Abb. 2
Abb. 3
Abb. 4
Abb. 5
Abb. 6
Abb. 7
Abb. 8
Abb. 9
Abb. 10
Abb. 11
Abb. 12
Abb. 13
Abb. 14
Abb. 15
Abb. 16
Abb. 17
Abb. 18
Abb. 19
Abb. 20
Abb. 21
Abb. 22
Abb. 23
Abb. 24
Abb. 25
Abb. 26
Beispiel-Graph 1
7
Beispiel-Graph 2
12
Anwendung von Dijkstra auf Beispiel-Graph 2
12
Kreuzung mit Modellierung in niedriger und hoher Granularität
29
Redundanz.
31
Matrix-Wegbaum für Matrix aus Tab. 2
37
Matrix-Wegbaum für Matrix aus Tab. 3
37
Matrix-Wegbaum für Matrix aus Tab. 3
38
Ein Beispiel-Weg zur Veranschaulichung der Straßentypwechselpunkte 39
Ein möglicher Matrix-Wegbaum für den Pfad aus Abb. 9
40
Ein weiterer möglicher Matrix-Wegbaum für den Pfad aus Abb. 9
40
Beispiel-Straßennetz
43
Straßenkarten-Ausschnitt in der Nähe von Mayen
47
Beispiel Fall 1 a, Fall 1 b
62
Beispiel Fall 2
63
Beispiel Fall 3
64
Beispiel Fall 4
65
Beispiel Fall 5
66
Beispiel Fall 6
67
Beispiel für Fall 2 nach AUTOBAHNNETZ_ERWEITERUNG
71
Abbildung für Beispiel 1
73
Abbildung für Beispiel 2
74
Abbildung für Beispiel 3
75
Abbildung für Beispiel 4
76
Abbildung für Beispiel 5
76
Screenshot des Straßennetz-Editors
85
v
Tabellenverzeichnis
Tab.
Tab.
Tab.
Tab.
Tab.
Tab.
1
2
3
4
5
6
Anwendung von Floyd auf Beispiel-Graph 2
Floyd-Wege-Matrix für einen Pfad von 0 nach 7
Eine Variante der Floyd-Wege-Matrix für einen Pfad von 0 nach 7
Eine weitere Variante der Floyd-Wege-Matrix für einen Pfad von 0 ...
Anwendung des Algorithmus FLOYD-WEGE-MATRIX-OPTIMIERUNG...
Gegenüberstellung asymptotischer Eigenschaften von kürzeste-Weg-...
vi
21
35
35
36
43
83
Kurzfassung/Abstract
In dieser Diplomarbeit ist ein hierarchisches Verfahrens entwickelt worden zur
Bestimmung exakter kürzester Wege in einem Straßennetz – eine bestimmte Art von
gerichteten, gewichteten Graphen. Dazu verwenden wir unter anderem eine in dieser
Diplomarbeit hergeleitete Variante der Wege-Matrix des Floyd-Algorithmus für
Straßennetze, welche auch allein weitere sinnvolle Anwendungen hat. Diese Matrix
ermöglicht die Beantwortung bestimmter Anfragen bzgl. eines kürzesten Weges P in
einem Straßennetz in o(|P|) Zeit bei Θ(n2) Speicherplatzbedarf. Das, in Bezug auf
Speicherplatzverbrauch und Laufzeit heuristische, hierarchische Verfahren generiert im
Best-Case Datenstrukturen mit Speicherplatzbedarf von Θ(|V[H]|2), wobei |V[H]| der
Komplexität des Autobahn(unter)-netzes entspricht. Diese Datenstrukturen können zur
Beantwortung von Anfragen nach kürzesten Wegen benutzt werden bei einer Laufzeit von
Θ(|P|). Es gibt gute Argumente dafür, dass der Best-Case bei Modellierungen von
Straßennetzen aus der realen Welt eintritt. Spezielle, zu der Variante der Floyd-WegeMatrix passende Anfragen, können mit den Datenstrukturen sogar in o(|P|) Zeit
beantwortet werden.
Schlagwörter:
Hierarchisch, Straßennetz, kürzeste, exakte, Weg, Floyd, Matrix, Heuristik
In this thesis a certain hierarchical method has been developed which can answer shortestpath-queries in a road network – a certain type of directed, weighted graph. For that
purpose we present a new variant of the shortest-path-matrix of Floyd’s algorithm, which
has also applications stand-alone. This matrix is capable of anwering certain queries
concerning a shortest path P in a road network in o(|P|) time and Θ(n2) space. The
hierarchical method, which is a heuristic in terms of running time and space, generates in
the best-case datastructures of Θ(|V[H]|2) space with |V[H]| being the complexity of the
motorway network of the original road network. These datastructures can be used to
answer shortest-path-queries in Θ(|P|) time. There are good arguments that road networks
of the real world result in the best-case of the hierarchical method. The datastructures can
also answer certain queries, that concern shortest-paths and fit to the variant of Floyd’s
shortest-path-matrix, in time o(|P|).
Keywords: hierarchical, road, network, shortest, exact, path, floyd, matrix, heuristic
vii
Vorwort
Das Vorwort möchte ich nutzen, um allen, die mir bei der Diplomarbeit und dem
bisherigen Studium geholfen haben, zu danken. Insbesondere möchte ich Christian Vogt
und Jörg Wagner für ihr Korrekturlesen danken. Außerdem möchte ich den Professoren
Rainer Manthey und Lutz Plümer für die gute Betreuung danken. Nicht zuletzt möchte ich
mich natürlich auch bei meinen Eltern, die mir das Studium ermöglicht haben, bedanken.
viii
1
Einleitung
Das Problem, von Punkt A möglichst schnell nach Punkt B zu kommen, ist wohl schon
seit der Steinzeit eines der wichtigen und häufig auftretenden Probleme der Menschheit. In
der Steinzeit wurde dies sehr intuitiv gelöst und wahrscheinlich noch kaum als „Problem“
aufgefasst: Man geht oder rennt möglichst entlang der Luftlinie von Punkt A nach Punkt
B. Wenn das Ziel nicht zu sehen war, mussten die Sonne, die Sterne und die Erinnerung
den Weg weisen. Mit der Erfindung von Karte und Kompass wurde dies, wenn man
einmal damit umgehen konnte, einfacher. Es wurde dann sogar möglich, Meere zu
überqueren, auf denen man nichts als Wasser sah. Mit der Zeit wurden immer mehr
Transportmittel erfunden, mit denen man sich immer schneller bewegen konnte.
Viele dieser Transportmittel benötigten einen ebenen Boden und es wurden Straßen und
später Schienen gebaut. Da diese Transportmittel, die sich auf Straßen und Schienen
bewegten, viel schneller als jene wurden, die sich über fast jedes Gelände bewegen
konnten, lohnte es sich bald nicht mehr, das inzwischen gut ausgebaute Straßen- und
Schienennetz auf dem Weg von Punkt A nach Punkt B zu verlassen. Durch die
zunehmende Erweiterung und Verdichtung der Straßennetze, wurden Karten für
jedermann immer wichtiger. Die Beschriftung der Straßen mit Straßennamen macht die
Orientierung und Wegsuche anhand einer Karte ungemein einfacher.
Heutzutage ist ein gut ausgebautes Straßennetz ubiquitär, genauso wie gute Karten –
zumindest in den Industrienationen. Die Preise für ein Notebook oder eine Uhr mit GPS
sind für jedermann erschwinglich. Daher kommt der Routenplanung mit Hilfe des
Computers eine immer größere Bedeutung zu.
Offensichtlich haben Straßennetze viel Ähnlichkeit mit Graphen. Inzwischen ist das
Problem, in einem gegebenen Graphen kürzeste Wege zwischen Knoten zu finden, eines
der klassischen Probleme der Graphentheorie und wird bereits seit mehr als 40 Jahren
intensiv studiert. Ein Grund liegt darin, dass dieses Problem in sehr vielen Anwendungen
– entweder als direktes stand-alone Problem oder als Unterproblem eines komplexeren
Problems – auftritt. Beispiele für Anwendungen, die mehr oder weniger nur aus diesem
Problem bestehen, sind natürlich die Routenplanung, Transport-Probleme, ProjektManagement und DNA-Sequenzierung. Beispiele für Anwendungen, bei denen kürzesteWeg-Probleme nur als kleines Teilproblem auftreten, sind die Approximation von
bestimmten Funktionen und das Knapsack Problem. (siehe [HASS00], S. 3).
Obwohl im Gebiet der kürzeste-Weg-Probleme in der Graphentheorie schon lange
geforscht wird, ist es noch nicht abgegrast. Zwar werden wahrscheinlich keine neuen
Algorithmen gefunden werden können, deren worst-case-Laufzeiten bei der Ausgabe
exakter kürzester Wege signifikant unter denen der schon gefundenen sind, aber es gibt
Forschungsbedarf im Bereich der Heuristiken und spezieller Verfahren für bestimmte
Arten von Graphen (wie z.B. Straßennetze).
1
Die Zielsetzung dieser Diplomarbeit ist die Entwicklung eines hierarchischen Verfahrens
zur Bestimmung exakter kürzester Wege in einem Straßennetz – eine bestimmte, in dieser
Diplomarbeit definierte, Art von gerichteten, gewichteten Graphen. Dazu verwenden wir
unter anderem eine in dieser Diplomarbeit hergeleitete Variante der Wege-Matrix des
Floyd-Algorithmus.
Dieses Verfahren teilt das gesamte Straßennetz anhand von Verwaltungsstrukturen, wie
z.B. Landkreisen, in einzelne, möglichst disjunkte Teile auf und ein möglichst das ganze
Straßennetz überdeckendes, aber nicht besonders dichtes Netz von Straßen, auf denen man
sich schnell bewegen kann – normalerweise Autobahnen. Mit Hilfe dieser Aufteilung ist
bei modellierten realen Straßennetzen zu erwarten, dass sich kürzeste Wege zwischen
Knoten ähnlich effizient wie bei der Verwendung einer vorberechneten Floyd-WegeMatrix bestimmen lassen, aber bei geringerem Speicherplatzbedarf.
Der Teil des Verfahrens, der das Straßennetz aufteilt, ist heuristisch und beinflusst den
Speicherplatzbedarf für die Datenstrukturen zur kürzesten-Weg-Bestimmung und die
Laufzeit der Bestimmung kürzester Wege. Es werden aber immer exakte kürzeste Wege
bestimmt.
Die Diplomarbeit gliedert sich folgendermaßen:
In Kapitel 2 führe ich grundlegende Definitionen der Graphentheorie bzgl. der
Bestimmung kürzester Wege ein. Danach wird eine kleine Übersicht über Unterklassen
der kürzeste-Weg-Probleme gegeben und über bekannte Algorithmen zur Lösung dieser.
Im Anschluss daran betrachten wir den Algorithmus von Dijkstra und den Algorithmus
von Floyd sehr detailliert. Der Abschnitt über den Algorithmus von Dijkstra ist nicht zum
Verständnis der folgenden Kapitel nötig und kann bei der Lektüre weggelassen werden.
Das Kapitel über den Algorithmus von Floyd sollte aber zumindest „überflogen“ werden,
weil das Kapitel 4 und später auch das Kapitel 5 viel damit zu tun hat.
Kapitel 3 definiert eine spezielle Art von Graph: das Straßennetz. Mit diesem beschäftigen
sich die nachfolgenden Kapitel intensiv. Dieses Straßennetz ist natürlich nur ein
theoretisches Gebilde, um reale Straßennetze zu modellieren. Was bei einer solchen
Modellierung zu beachten ist, wird in Abschnitt 3.2 behandelt und ist eher leicht
verdaulicher Stoff, den man aber bei den späteren Kapiteln im Hinterkopf haben sollte.
Zuletzt gehen wir kurz auf die Unterschiede und auf die Gemeinsamkeiten von Graphen
und Straßennetzen und die dadurch bedingten Konsequenzen für uns ein.
Kapitel 4 ist neben Kapitel 5 ein Schwerpunkt dieser Diplomarbeit. Hier geht es um die
Herleitung einer bestimmten Variante der Floyd-Wege-Matrix, welche interessante
Eigenschaften vorweist. Nach der Beobachtung, dass die Floyd-Wege-Matrix auch zu
einer etwas anderen Weise der Speicherung kürzester Wege fähig ist, als in Kapitel 2
vorgestellt, leiten wir eine für unsere Zwecke günstige Variante der Matrix her. Den
endgültigen Existenzbeweis und Startschuss für die Anwendung dieser Variante liefert der
Algorithmus aus Abschnitt 4.3, welcher eine gegebene Floyd-Wege-Matrix in eine mit
2
optimaler Struktur transformiert. In Abschnit 4.4 betrachten wir eine Anwendung für
diese, welche wir im folgenden Kapitel auch noch einmal aufgreifen werden:
In Kapitel 5 geht es um die Herleitung einer bestimmten hierarchischen Datenstruktur zur
Speicherung eines Straßennetzes. Wir beginnen dazu mit der sehr intuitiven Idee für die
Datenstruktur, die wir dann im nächsten Abschnitt formal auf den Punkt bringen. Im
Abschnitt 5.1.3 entwickeln wir einen Algorithmus zur Bestimmung exakter kürzester
Wege in dem hierarchischen Straßennetz. Abschnitt 5.2 beschäftigt sich mit der Frage, wie
wir aus einem Straßennetz ein solches hierarchisches gewinnen können. Dazu überlegen
wir uns in Abschnitt 5.2.1, welche Kriterien diese möglichst erfüllen sollten. Im darauf
folgenden Abschnitt betrachten wir eine Heuristik, die aus einem Straßennetz ein
hierarchisches generiert. In Abschnitt 5.2.3 gehen wir auf das worst-case-Verhalten der
Heuristik ein. In Abschnitt 5.3 legen wir uns erstmals auf eine Datenstruktur zur
Speicherung des hierarchischen Netzes fest: Die Variante der Floyd-Wege-Matrix. Dazu
analysieren wir neben dem worst-case das erhoffte Verhalten der hergeleiteten
Algorithmen mit dieser Datenstruktur für Straßennetze.
In Kapitel 6 gehen wir kurz auf die in der Bearbeitungszeit dieser Diplomarbeit
entstandene Java-Implementation der hergeleiteten Algorithmen und Datenstrukturen und
eines graphischen Editors für Straßennetze ein.
3
2
Kürzeste Wege in der klassischen Graphentheorie
In diesem Kapitel möchte ich die für die nachfolgenden Kapitel benötigten Grundlagen
bzgl. kürzester Wege in Graphen wiederholen, so dass jene ohne weiteres Nachschlagen in
sonstiger Literatur verständlich sein sollten.
Dazu fangen wir in Abschnitt 2.1 mit grundlegenden Definitionen und zwei Lemmata der
Graphentheorie in Hinblick auf kürzeste Wege und kürzeste-Weg-Probleme an. In
Abschnitt 2.2.1 betrachten wir eine Klassifikation von kürzeste-Weg-Problemen bzgl.
verschiedener Graphenklassen und geben eine Übersicht von Algorithmen zur Lösung
dieser. Danach beschäftigen wir uns in den Abschnitten 2.2.2 und 2.2.3 mit zweien dieser
Algorithmen und insbesondere mit den von ihnen zurückgegebenen Datenstrukturen im
Detail: Dem Algorithmus von Dijkstra und dem von Floyd. Das Lesen des Kapitels über
den Algorithmus von Dijkstra ist nicht zum Verständnis der späteren Kapitel notwendig1;
das Kapitel über den Algorithmus von Floyd wahrscheinlich schon – abhängig vom
individuellen Kenntnisstand des Lesers in dieser Thematik.
Als Literatur diente mir in diesem Kapitel [LEDA99], [BLUM98], [BRAN94] und
[KRUM00].
2.1 Einleitung und grundlegende Definitionen
Bevor wir jetzt auf die Algorithmen zur Lösung von kürzeste-Weg-Probleme zu sprechen
kommen, werden wir in diesem Abschnitt zuerst Grundlegendes definieren (die meisten
der folgenden Definitionen sind aus [LEDA99]):
Sei G = (V, E, w) ein (endlicher, schlichter,)2 gewichteter und gerichteter Graph mit
E ⊆ (V × V ) \ {(v, v) | v ∈ V } (G enthält also keine Schlingen) und mit Kostenfunktion
w : E → ℜ der Kanten auf die reellen Zahlen. Es gelte |V| = n < ∞ und |E| = m < ∞. Die
Kosten oder das Gewicht einer Kante werde ich in Zukunft synonym auch als Länge
bezeichnen. Aus ästhetischen Gründen und weil es allgemein so üblich ist, schreiben wir
w(u, v) für Kanten e = (u, v) anstatt w((u, v)) wie es eigentlich richtiger ist.
1 Anfangs, zu Beginn der schriftlichen Ausarbeitung der Diplomarbeit, war dies etwas anders gewesen und später wollte
ich das Kapitel nicht einfach löschen. Der interessierte Leser ist herzlich zur Lektüre dieses Kapitels eingeladen.
2 Wenn ich im folgenden von gewichteten, gerichteten Graphen spreche, dann sind sie auch immer – wie es auch sonst
fast immer so ist – endlich und schlicht, d.h. Knotenmenge und Kantenmenge sind endlich, enthalten keine
Schlingen und keine parallelen Kanten (siehe [BRAN94], S. 12 zu einer allgemeineren Definition von Graphen,
welche auch Schlingen und parallele Kanten zulässt).
4
Unter einem Weg oder einem Pfad P von v0 nach vk verstehen wir eine Folge von Knoten
und Kanten [v0, e1, v1, e2, ..., vk-1, ek, vk] mit ei = (vi-1, vi) für i = 1,...,k. Anstatt dieser
Notation werde ich auch die verkürzten (und ebenfalls eindeutigen) Notationen
[v0, v1,..., vk-1, vk] oder [e1, e2, ..., ek-1, ek] verwenden. Wir sagen, Knoten w ist von Knoten v
erreichbar, gdw. es einen Pfad von v nach w im betrachteten Graphen gibt. Ein solcher
Pfad P heißt einfach, falls vi ≠ vj für 0 ≤ i < j ≤ k. Die Kardinalität oder ungewichtete
Länge |P| eines Pfades P ist die Anzahl der Kanten von P. Wir erweitern die
Kostenfunktion auf Pfade P folgendermaßen: w( P ) := ∑ w(e) . Für alle Knoten
Kanten e ∈P
v ∈ V definieren wir die Kosten des trivialen Pfades von v zu v – der Pfad, der keine
Kanten enthält – als Null. Wie oben nennen wir die Kosten w(P) eines Pfades P auch
Länge von P (welche i.A. nicht mit der ungewichteten Länge übereinstimmt). Ein Kreis ist
ein nicht-trivialer Pfad, dessen Startknoten auch sein Zielknoten ist. Ein negativer Kreis ist
ein Kreis, welcher negative Länge hat.
Für alle zwei Knoten v, w definieren wir mit δ (v, w) die minimale / kürzeste Weg- /
Pfadlänge eines Pfades von v nach w folgendermaßen:
⎧inf({w( P) : P ist (endlicher ) Pfad von v nach w}), falls w von v erreichbar
⎩+ ∞, sonst
δ (v, w) := ⎨
Da die Menge der Pfade von v nach w i.A. unendlich ist (weil die Pfade ja nicht
notwendigerweise einfach sein müssen), ist nicht direkt klar, ob es immer einen
(endlichen) Pfad gibt, dessen Länge δ (v, w) beträgt. Folgendes Lemma, basierend auf
[LEDA99], S. 317, verschafft darüber Klarheit:
Lemma 1:
Sei G = (V, E, w). Für alle Knoten v, w ∈ V gilt:1
a) δ (v, w) = +∞ gdw. es keinen Pfad von v nach w im betrachteten Graphen gibt.
b) δ (v, w) = −∞ gdw. es einen Pfad von v nach w gibt, welcher einen negativen Kreis
enthält.
c) − ∞ < δ (v, w) < +∞ gdw. w von v aus erreichbar ist und es keinen Pfad von v nach
w gibt, welcher einen negativen Kreis enthält. δ (v, w) entspricht dann der
(minimalen) Länge eines einfachen Pfades von v nach w.
Beweis:
Zu a)
1 In diesem Kapitel verwenden wir die in der Mathematik und Informatik üblichen Rechenregeln und Ordnung für
ℜ ∪ {−∞, + ∞} : −∞ < x < +∞, − ∞ + x = −∞, + ∞ + x = +∞ für alle x ∈ ℜ
5
⇒) Folgt direkt aus der Definition und der Tatsache, dass kein endlicher Pfad unendliche
Länge haben kann.
⇐) Folgt direkt aus der Definition.
Zu b)
⇒) Falls δ (v, w) = −∞ , dann ist w von v aus erreichbar. Da kein endlicher Pfad (negativ)
unendliche Länge haben kann, kann es nur so sein, dass sich einfache, endliche Pfade
durch Hinzufügen von Kreisen im Grenzwert ins (negativ) Unendliche verlängern
lassen. Da es nur endlich viele Kreise im endlichen Graphen G gibt, muss zumindest
einer dieser immer weiter (bis unendlich oft im Grenzwert) durchlaufen werden.
Dessen Länge muss dann auch negativ sein, da sonst ja keine negativ unendliche
Länge im Grenzwert auftauchen könnte. Natürlich muss dieser Kreis auch auf dem
Weg von v nach w liegen.
⇐) Die Kosten eines solchen Pfades, der einen negativen Kreis enthält, kann man durch
jeden weiteren Durchlauf dieses Kreises verkürzen und damit jede negative
Kostenzahl unterschreiten. Also ist das Infinum über alle Pfade von v nach w gleich ∞.
Zu c)
⇒) Da − ∞ < δ (v, w) < +∞ , folgt aus a) und b), dass es keinen Pfad von v nach w gibt, der
einen negativen Kreis enthält und dass es einen Pfad von v nach w gibt. Zu zeigen ist
noch, dass es einen solchen Pfad gibt, der einfach ist und der eine Länge von δ (v, w)
hat. Dazu schauen wir uns einen Pfad P von v nach w mit Länge δ (v, w) an. Dieser
existiert wegen der Definition von δ. Angenommen, dieser Pfad hätte einen (nichtnegativen) Kreis P, dann könnte man ja den Pfad von v nach w im ungewichteten
Sinne dadurch verkürzen, indem man den Kreis P weglässt. Aus der Wahl des Pfades
P und der Definition von δ folgt, dass dieser neue entsprechend verkürzte Pfad P’
auch Länge von δ (v, w) hat (und dementsprechend der Kreis (gewichtete) Länge von
null). Auf diese Weise kann man alle Kreise entfernen und erhält so einen legalen
einfachen Pfad von v nach w mit Länge δ (v, w) . Also existiert immer ein solcher.
⇐) w ist also von v aus erreichbar und es gibt keinen Pfad von v nach w, der einen
negativen Kreis enthält. Aus den Äquivalenzen in a) und b) folgt dann direkt
− ∞ < δ (v, w) < +∞ . Daraus und aus dem Beweis der Hinrichtung folgt dann, dass es
einen einfachen Pfad von v nach w mit Länge δ (v, w) gibt.
‫ڤ‬
Einen kürzesten Pfad / Weg definieren wir dann folgendermaßen: Ein Pfad P von u nach v
ist kürzester Pfad / kürzester Weg von u nach v gdw. w(P) = δ (v, w) . Daraus, aus Lemma
1 und den „Rechenregeln“ für endliche und unendliche Zahlen folgt dann, dass ein
6
kürzester Pfad von u nach v genau dann existiert, falls − ∞ < δ (v, w) < +∞ und dass es
immer einen solchen gibt, der einfach ist. Nun aber erst einmal ein Beispiel (siehe Abb. 1):
δ(a, f) = +∞
δ(a, b) = 3
1
b
f
δ(a, c) = -∞
δ(a, e) = -∞
-7
c
15
1
3
e
4
a
5
d
δ(a, d) = -∞
δ(a, a) = 0
Abb. 1: Beispiel-Graph 1. In diesem Beispiel gibt es den negativen Kreis [d, (d, e), e, (e, d),
d], welcher dafür sorgt, dass c, d und e negativ unendliche Distanz von a haben. Es
nur zwei kürzeste Pfade vom Knoten a aus: den trivialen, leeren Pfad von a nach a
und den Pfad [a, (a, b), b] von a nach b.
Bevor wir auf die eigentlichen Algorithmen zur Berechnung der oben definierten
kürzesten Wege zu sprechen kommen, ist es nützlich (und interessant), zuvor noch ein
paar allgemeine Eigenschaften kürzester Wege zu betrachten, da diese in vielen
Algorithmen – mehr oder weniger explizit – ausgenutzt werden. Nachfolgendes Lemma
sagt aus, dass Teilpfade von kürzesten Pfade wiederum selbst kürzeste Pfade sind:
Lemma 2: (aus [BLUM98], S. 240)
Sei G = (V, E, w) und sei P = [v1,v2, ..., vk] ein kürzester Pfad von v1 nach vk in G. Dann
gilt für alle 1 ≤ i ≤ j ≤ k, dass der Teilpfad Pij := [vi,vi+1, ..., vj] von P ein kürzester Pfad von
vi nach vj ist.
Beweis:
Angenommen, es gäbe einen kürzeren Pfad Pij’ von vi nach vj in G, also w(Pij’) < w(Pij).
Betrachte dann den Pfad P’ := P1i, Pij’, Pjk. Dann gilt:
w(P’) = w(P1i) + w(Pij’) + w(Pjk)
< w(P1i) + w(Pij) + w(Pjk)
= w(P).
Dies ist aber ein Widerspruch dazu, dass P ein kürzester Pfad von v1 nach vk ist. Also ist
Pij ein kürzester Pfad von vi nach vj.
‫ڤ‬
7
2.2 Algorithmen zur Berechnung kürzester Wege
2.2.1 Übersicht
In diesem Abschnitt möchte ich eine kleine Übersicht der Algorithmen zur Lösung von
kürzeste-Weg-Problemen1 geben. Als Literatur diente mir hier [BLUM98], [LEDA99],
[KRUM00] und [BRAN94].
Unter einem kürzeste-Weg-Problem versteht man normalerweise die Berechnung eines
oder mehrerer kürzester Wege in einem gegebenen Graphen. Dabei unterscheidet man
üblicherweise zwischen folgenden Varianten von kürzeste-Weg-Problemen:
•
Das Einzelpaar-kürzeste-Weg-Problem (single-pair shortest-path problem oder
single-source single-sink shortest-path problem): Gegeben G = (V, E, w) und zwei
Knoten s, t ∈ V , möchte man einen kürzesten Pfad von s nach t finden.
•
Das Einzelquelle-kürzeste-Weg-Problem (single-source shortest-path problem):
Gegeben G = (V, E, w) und einen (Quell-)Knoten s ∈ V , soll für jeden Knoten v ∈ V
ein kürzester Pfad von s zu v gefunden werden.
•
Das Alle-Paare-kürzeste-Weg-Problem (all-pairs shortest-path problem): Hier möchte
man, gegeben G = (V, E, w), für jedes Paar u, v ∈ V einen kürzesten Pfad von u nach v
finden.
Man sieht, dass man natürlich mit der Lösung des alle-Paare-kürzeste-Weg-Problems auch
die beiden anderen gelöst hat. Ausserdem löst das Einzelquelle-kürzeste-Weg-Problem
auch das Einzelpaar-kürzeste-Weg-Problem. Interessanterweise ist für das zweite Problem
auch kein asymptotisch effizienteres Verfahren bekannt, als das erste Problem zu lösen.
Je nachdem, welche Eigenschaften der betrachtete Graph erfüllt, lassen sich verschieden
effiziente Algorithmen zur Lösung der oben genannten Probleme verwenden. Für das
Einzelquelle-kürzeste-Weg-Problem kennt man folgende Verfahrensweisen2:
Ist der Graph ungewichtet bzw. haben alle Kanten das gleiche positive Gewicht, so lassen
sich kürzeste Wege in Linearzeit O(G) := O(n+m) des Graphen bestimmen.
1 Ich dekliniere das „kürzeste-Weg“ von „kürzeste-Weg-Probleme“ nicht, da es so am üblichsten zu sein scheint.
2 Die hier skizzierten oder genannten Algorithmen sind die ältesten und bekanntesten kürzeste-Weg-Algorithmen, die
man in den meisten Lehrbüchern finden kann. Zu manchen der angesprochenen Probleme gibt es inzwischen
andere Algorithmen, welche leicht verbesserte Laufzeiten vorweisen, aber normalerweise viel komplizierter sind.
Eine Betrachtung solcher Optimierungen würde den Rahmen dieses Kapitels sprengen.
8
In sog. dags, directed acyclic graphs, also gerichtete, kreisfreie Graphen, lassen sich mit
Hilfe einer topologischen Sortierung des gegebenen Graphen (welche in O(G) berechenbar
ist) in Linearzeit alle kürzesten Wege von einem Knoten aus berechnen.
Hat der betrachtete Graph nur positive Kantengewichte, so liefert der Algorithmus von
Dijkstra (siehe 2.2.2) in Zeit O(n2) bei Verwendung einfacher Datenstrukturen (bei
komplizierteren geht es z.T. noch besser, s.u.) kürzeste Wege.
Kommen auch negative Kantengewichte im Graphen vor, so gibt der Algorithmus von
Dijkstra nicht mehr notwendigerweise die kürzesten Wege aus (sofern diese dann
überhaupt existieren). Der Algorithmus von Bellman-Ford dagegen gibt in Zeit O(n*m)
korrekt die kürzesten Wege aus oder terminiert mit der Meldung, dass es im EingabeGraphen einen negativen Kreis gibt. Verbesserte Versionen des Algorithmus können in der
gleichen Zeit bei Existenz von negativen Kreisen sogar den Teil des Graphen, der die
negativen Kreise und davon abhängige Knoten (also Knoten mit Distanz -∞) enthält,
ausgeben, sowie den Teil, der nicht von den negativen Kreisen betroffen ist.
Deutlich schwieriger wird das kürzeste-Weg-Problem, wenn man an einfachen Pfaden
interessiert ist – zumindest dann, wenn negative Kreise vorkommen1. Dieses ist nämlich
NP-vollständig, weil die Lösung auch eine Lösung des NP-vollständigen Problems der
Berechnung der längsten einfachen Pfade im Graphen G’ := (V, E, -w) (wie G, nur mit
einer mit -1 multiplizierten Kostenfunktion) ist.
Das alle-Paare-kürzeste-Weg-Problem lässt sich durch n-maliges Lösen des Einzelquellekürzeste-Weg-Problem lösen, was zum Teil durchaus sehenswerte Laufzeiten ergeben
kann2. Der Algorithmus von Floyd, welcher einen zentralen Bestandteil in dieser
Diplomarbeit einnimmt und in 2.2.3 noch ausführlich beschrieben wird, gibt nach O(n3)
Zeit entweder alle kürzeste Wege aus oder die Meldung, dass ein negativer Kreis im
Graphen vorhanden ist.
Da wir nun einen kleinen Überblick über die Komplexitäten der Bestimmung kürzester
Wege in verschiedenen Klassen von Graphen und über Algorithmen zur Lösung von
kürzeste-Weg-Probleme haben, wollen wir im nächsten Abschnitt zwei Vertreter dieser
Algorithmen im Detail betrachten.
1 Falls keine negativen Kreise im betrachteten Graphen vorkommen, liefern die zuvor genannten Algorithmen für das
kürzeste-Weg-Problem (natürlich) immer einfache Wege. Die Betrachtung kürzester einfacher Wege als eigenes
Problem macht demnach nur Sinn bei Vorhandensein negativer Kreise im Graphen, also nicht z.B. bei
azyklischen Graphen oder Graphen mit nur positiven Kantengewichten.
2 Siehe hierzu vielleicht [BLUM98], S. 248 ff.. Dort wird nämlich eine interessante Transformation eines Graphen mit
allgemeinen Kantengewichten (allerdings bei Fehlen von negativen Kreisen) auf positive beschrieben, welche
kürzeste Wege nicht ändert und in Zeit O(nm) durchführbar ist.
9
2.2.2 Im Detail: Algorithmus von Dijkstra
Ich beschreibe jetzt den Algorithmus von Dijkstra als Stellvertreter für Einzelquellekürzeste-Weg-Algorithmen, da dies wohl der bekannteste kürzeste-Weg-Algorithmus
überhaupt ist und man an ihm eine Möglichkeit der komprimierten Speicherung kürzester
Wege kennenlernt. Im Gegensatz zu dem Algorithmus von Bellman-Ford müssen bei dem
Algorithmus von Dijkstra die Kantengewichte positiv (≥ 0) sein. Dafür hat er eine bessere
Laufzeit.
Bevor wir zum eigentlichen Algorithmus kommen, schauen wir uns an, wie man überhaupt
Wege und Distanzen vom Startknoten s zu allen anderen Knoten des Eingabe-Graphen
darstellen bzw. später mit dem Algorithmus zurückgeben kann: (folgende drei
Definitionen basieren auf [KRUM00], sind aber zum Teil für unsere Zwecke etwas
verändert)
Ein Wurzelbaum mit Wurzel s ist ein gerichteter Graph G = (V, E), für den gilt:
•
s ∈V
•
indegG(s) = 0, d.h. der Eingangsgrad von s (Anzahl Kanten, die in s eingehen) ist
0
•
indegG(v) = 1 für alle v ∈ V \{s}
•
G ist (schwach) zusammenhängend, d.h., wenn G’ die ungerichtete Version von G
sei, die man erhält, indem man die Kantenrichtungen in G ignoriert, dann ist G’
zusammenhängend bzw. es gibt jeweils einen Weg zwischen allen möglichen
Knotenpaaren von G’
Aus der Definition von Wurzelbaum folgt direkt, dass es sich dabei um einen Baum
handelt, an dessen Spitze (Wurzel) sich s befindet und es genau einen Pfad von s zu jedem
anderen Knoten v ∈ V gibt.
Sei G = (V, E, w) ein gerichteter, gewichteter Graph. Ein kürzester Wegebaum / kürzester
Pfadbaum bzgl. G mit Wurzel s ist ein Wurzelbaum T = (V’, E’) ⊆ G mit Wurzel s mit
folgenden Eigenschaften:
•
V’ = {v ∈ V | −∞ < δ ( s, v) < +∞} , d.h. V’ enthält alle (und auch nur die) Knoten,
welche von s aus erreichbar sind
•
Für alle v ∈ V ' \{s} ist der (eindeutige) Weg von s nach v in T ein kürzester Weg
von s nach v in G
Der gleich folgende Algorithmus von Dijkstra gibt einen solchen kürzesten Wegebaum
nicht direkt zurück, sondern in Form einer Funktion / Array π: V → V ∪ {nil} . Diese
Funktion π induziert einen sog. Vorgängergraphen Gπ, der folgendermaßen definiert ist:
Gπ = (Vπ Eπ) mit:
Vπ = { v ∈ V | π(v) ≠ nil} ∪ {s} und
10
Eπ = {( π(v), v) | v ∈ Vπ und v ≠ s}
Man sieht, dass ein solcher Vorgängergraph von der Struktur her kürzeste Wegebäume
speichern kann, aber auch Bäume, die keine kürzesten Wegebäume sind (weil er auch
Kreise enthalten und unzusammenhängend sein kann). Es gilt also später zu zeigen, dass
der durch die zurückgegebene Funktion induzierte Vorgängergraph ein kürzester
Wegebaum ist. Die Distanzen von s zu allen anderen Knoten v δ ( s, v) werden auch in
Form einer Funktion oder eines Arrays d zurückgegeben:
Algorithmus: DIJKSTRA (aus [BLUM98], S. 244)
Eingabe: a) gerichteter, gewichteter Graph G = (V, E, w) mit w(u, v) ≥ 0 für alle
(u, v) ∈ E
b) Quellknoten s ∈ V
Ausgabe: d(v) = δ ( s, v) für jeden Knoten v ∈ V und ein kürzester Wegebaum Tπ
Methode:
d(s) := 0;
π(s) := nil;
for all v ∈ V \{s}
do
d(v) := ∞;
π(v) := nil;
od
Q := V;
while Q ≠ Ø
do
finde u ∈ Q mit d(u) = min({d(v) | v ∈ Q });
Q := Q \ {u};
for all v ∈ Q mit (u, v) ∈ E
do
if d(v) > d(u) + w(u, v)
then
d(v) := d(u) + w(u, v);
π(v) := u;
fi
od
od
Gib {d(v) | v ∈ V } und Tπ aus.
‫ڤ‬
Bevor wir auf die Korrektheit des Algorithmus zu sprechen kommen, schauen wir uns ein
Beispiel an (Abb. 2):
11
1
4
5
1
2
3
2
9
1
3
2
1
2
1
1
8
6
3
3
8
7
0
Abb. 2: Beispiel-Graph 2. Gerichteter, gewichteter Graph G = (V, E, w) mit V = {0, ..., 9}. Die
Beschriftungen innerhalb der Knoten sind die Knotenbezeichnungen und die Beschriftungen an
den Kanten e stellen die Kantengewichte w(e) dar.
δ(0, 3) = 4
3
δ(0, 0) = 0
δ(0, 1) = 1
δ(0, 2) = 2
0
1
2
δ(0, 6) = 4
6
δ(0, 9) = 3
δ(0, 4) =5
4
δ(0, 7) = 7
7
8
δ(0, 8) = 6
5
δ(0, 5) = 5
9
Abb. 3: Anwendung von Dijkstra auf Beispiel-Graph 2. Dies ist der kürzeste Wegbaum (mit den
kürzesten Distanzen als Ergänzung eingetragen) , der sich aus der Vorgängerfunktion π ergibt,
wenn man den Algorithmus von Dijkstra auf den Beispiel-Graphen 2 (Abb. 2) anwendet mit
Quellknoten s = 1.
Die Korrektheit des Algorithmus von Dijkstra zeige ich auf allgemeinere Weise, als
eigentlich nötig, da man auf diese Art ein paar Einblicke in das kürzeste-Weg-Problem an
sich bekommt. Da es in diesem Kapitel nur um die Berechnung kürzester Pfade von dem
12
einen Knoten s aus geht, werden wir die Notation der Minimaldistanzfunktion δ etwas
verkürzen, indem wir δ(v) anstatt δ(s, v) schreiben. Folgendes Lemma, welches man als
Kern vieler Korrektheitsbeweise von Einzelquelle-kürzeste-Weg-Algorithmen verwenden
kann (so wie ich es hier mache), sagt etwas über die Beziehung zwischen vorläufigen
Distanzfunktionen d und der Minimal-Distanzfunktion δ aus1:
Lemma 3: (aus [LEDA99], S. 318)
Sei G = (V, E, w):
a) Für die Funktion δ gilt:
i.
δ(v) = min({δ(u) + w(e) | e = (u, v) ∈ E }) für v ≠ s
ii.
δ(s) = min({0, min({δ(u) + w(e) | e = (u, s) ∈ E })})
b) Falls d eine Funktion von V nach ℜ ∪ {−∞,+∞} ist, welche nachstehende
Eigenschaften erfüllt, dann gilt: d(v) = δ(v) für alle v ∈ V
i.
d(v) ≥ δ(v) für alle v ∈ V ,
ii.
d(s) ≤ 0 und
iii.
d(v) ≤ d(u) + w(u, v) für alle e = (u, v) ∈ E
Beweis:
Zu a) i)
Jeder Pfad von s nach v besteht aus einem Teilpfad von s zu einem Knoten u und einer
Kante von u nach v. Also gilt:
δ(v) = inf ({w(P) | P ist ein Pfad von s nach v})
= minu inf ({w(P’) + w(e) | P’ ist ein Pfad von s nach u und e = (u, v) ∈ E })
= min ({δ(u) + w(e) | e = (u, v) ∈ E }).
Zu a) ii)
Falls wegen eines negativen Kreises δ(s) = -∞ gilt, dann gibt es auch ein u mit δ(u) = -∞.
Also stimmt die Gleichung in diesem Fall.
Ansonsten ist ein kürzester Pfad von s nach s der triviale Pfad mit gewichteter und
ungewichteter Länge von 0 oder ein Kreis P mit gewichteter Länge von 0 und
ungewichteter Länge von > 0. Die Länge eines solchen Kreises beträgt nach a) i)
min({δ(u) + w(e) | e = (u, s) ∈ E })}) . Die Länge eines kürzesten Pfades von s nach s δ(s)
1 Diese vorläufigen / temporären Distanzfunktionen d, die von Algorithmen sukzessive verbessert (normalerweise
verkleinert) werden bis sie δ entsprechen, werden in der englisch-sprachigen Literatur als tentative bezeichnet
13
entspricht dann dem Minimum von 0 und der Länge eines solchen Kreises. Die Gleichung
stimmt also auch in diesem Fall.
Zu b)
Hierzu nehmen wir an, dass für ein v d(v) > δ(v) gelte. Daraus folgt wegen der Ordnung in
ℜ U {−∞,+∞} , dass δ(v) < +∞. Nun betrachten wir zwei mögliche Fälle:
Falls δ(v) > -∞, dann sei [s = v0, v1, ..., vk = v] ein kürzester Pfad von s nach v. Es gilt δ(s)
= 0 = d(s) und δ(vi) = δ(vi-1) + w(vi-1, vi) für alle 1 ≤ i ≤ k. Wegen der Annahme d(v) > δ(v)
gibt es mindestens ein i, so dass d(vi) > δ(vi). Wähle nun das Minimale solche i. Nun gilt
d(vi) > δ(vi) = δ(vi-1) + w(vi-1, vi) = d(vi-1) + w(vi-1, vi).
Dies ist aber ein Widerspruch gegen b) iii).
Ansonsten, falls also δ(v) = -∞, sei [s = v0, v1, ..., vi, ..., vj, ..., vk = v] ein Pfad von s nach v,
welcher einen negativen Kreis enthält. Ein solcher Pfad existiert nach Lemma 1. Der
Teilpfad von vi nach vj sei ein (einfacher) negativer Kreis. Wegen unserer Annahme d(v) >
δ(v) folgt nun d(v) > -∞ und wegen Eigenschaft b) iii) muss dann auch d(vl) > -∞ für alle 0
≤ l ≤ k gelten. Also,
d(vi) = d(vi)
, weil vi = vj
≤ d(vj-1) + w(vj-1, vj)
≤ d(vj-2) + w(vj-2, vj-1) + w(vj-1, vj)
≤ ...
...
j −1
≤ d(vi) + ∑l =i w(vl , vl +1 ) ,
und deshalb
∑
j −1
l =i
w(vl , vl +1 ) ≥ 0, was ein Widerspruch dazu ist, dass der Teilpfad von vi
nach vj ein negativer Kreis ist.
‫ڤ‬
Bevor wir nun zeigen, dass die vom Algorithmus von Dijkstra berechnete Funktion d die
Eigenschaften b) i) – iii) des vorigen Lemma erfüllt und damit die Korrektheit von d
zeigen, machen wir uns erstmal Gedanken über den zurückgegebenen Vorgängergraphen:
Lemma 4: (basiert auf [KRUM00], S. 74)
Sei G = (V, E, w) gerichteter, gewichteter Graph, s ∈ V ein Quellknoten und in G sei von s
aus kein Kreis negativer Länge erreichbar. Ein Algorithmus A initialisiere eine temporäre
Distanzfunktion d: V → ℜ ∪ {−∞,+∞} mit d(v) = ∞ für alle v ∈ V \{s} und d(s) = 0 und
eine Vorgängerfunktion π: V → V ∪ {nil} mit d(v) = nil für alle v ∈ V .Dann führe er eine
Anzahl von folgenden (atomaren) Verbesserungsschritten auf den Knoten durch:
VERBESSERE(u, v)
if d(v) > d(u) + w(u, v)
then
14
d(v) := d(u) + w(u, v);
π(v) := u;
fi
Dann sind folgende Eigenschaften jederzeit erfüllt:
a) Der durch π induzierte Vorgängergraph Gπ = (Vπ, Eπ) ist ein Wurzelbaum mit
Wurzel s
b) Gπ enthält für v∈ Vπ\{s} einen Weg P = [s = πk(v), ..., π(v), v]1 von s nach v der
Länge höchstens d(v).
Beweis:
Wir beweisen die Behauptungen a) und b) durch Induktion über die Anzahl der
Verbesserungsschritte m.
Induktionsanfang:
Falls m = 0, so ist Vπ = {s}, Eπ = Ø, d(s) = 0 und d(v) = +∞ für v ≠ s. In diesem Fall sind
Behauptung a) und b) erfüllt.
Induktionsannahme:
Die Behauptung gelte direkt nach dem (m-1). Schritt der while-Schleife.
Induktionsschritt: m-1 → m
Die beiden Aussagen gelten nach m-1 Verbesserungsschritten, und es werde ein weiterer
Verbesserungsschritt durchgeführt. Falls in diesem m. Schritt die Kondition der ifAnweisung false ergibt, also d(v) ≤ d(u) + w(u, v), dann ändert sich nichts an Gπ. In diesem
Fall sind also auch nach dem m. Schritt die Eigenschaften a) und b) erfüllt.
Falls d(v) > d(u) + w(u, v) im m. Schritt gilt, so wird d(v) auf d(u) + w(u, v) vermindert und
π(v) := u gesetzt. Dadurch wird in Gπ die Kante (u, v) hinzugefügt und entweder der
Knoten v hinzugefügt oder die alte Kante (x, v) vom früheren direkten Vorgänger x von v
entfernt.
Zu a)
Aus der Konstruktion von π und Gπ folgt direkt, dass Gπ immer genau |Vπ| - 1 Kanten
besitzt. Außerdem gilt indegG(s) = 0 und indegG(v) = 1 für alle v∈Vπ \{s}. Zu zeigen ist
nur noch, dass Gπ schwach zusammenhängend ist bzw. das alle Knoten von s aus
erreichbar sind.
War vorher π(v) = nil, also v ∉ Vπ, so wird Gπ nun eben um diesen Knoten v und um die
Kante (u, v) erweitert. Nach Induktionsvoraussetzung ist u von s aus in Gπ erreichbar und
damit auch v.
1 Hierbei sei π0(v) = v und πi(v) = π (πi-1(v)) für i > 0, sofern πi-1(v) ≠ nil
15
Falls vorher π(v) = x ≠ nil galt, dann wird die Kante (x, v) in Gπ durch (u, v) ersetzt. Da
nach Induktionsvorausstzung Gπ vor dem Tausch ein Wurzelbaum mit Wurzel s war,
genügt es zu zeigen, dass nach dem Tausch der Knoten v von s aus in Gπ erreichbar ist.
Wir betrachten nun zwei denkbare Fälle:
Falls u zuvor ein Nachfolger von v war, also der eindeutige Pfad von s nach u über v ging,
dann würde der Kantentausch zu einem Kreis führen, weil es ja immer noch einen Pfad
von v nach u gibt und jetzt noch eine Kante von u nach v. Wegen der nur |Vπ| - 1 Kanten
im Graphen wäre damit ein schwacher Zusammenhang von Gπ nicht möglich. Jetzt möchte
ich zeigen, dass dieser Fall nicht möglich ist: Nach Induktionsvoraussetzung von a) und b)
folgt, dass zuvor der eindeutige Pfad P = P1, P2 in Gπ von s nach u die Länge d(u) hatte,
wobei P1 der Teilpfad von s nach v ist und P2 der Teilpfad von v nach u. Es folgt w(P1) =
d(v) und w(P2) = d(u) – d(v). Der Kantentausch findet nur statt, wenn
⇔
d(v) > d(u) + w(u, v) =
=
0
>
w(P1) + w(P2) + w(u, v)
d(v) + w(P2) + w(u, v)
w(P2) + w(u, v)
w(P2) + w(u, v) ist die Länge des Kreises von v nach u nach v. Widerspruch zur
Voraussetzung der Nicht-Negativität aller von s aus erreichbaren Kreise.
Falls u zuvor kein Nachfolger von v war, dann ist nach dem Tausch gemäß
Induktionsvoraussetzung v von s aus durch einen Pfad von s nach u nach v erreichbar (und
natürlich auch alle Nachfolger von v).
Zu b)
Die Tatsache, dass die Pfade P von s zu allen anderen Knoten v in Gπ die Struktur P = [s =
πk(v), ..., π(v), v] haben, folgt direkt aus a) sowie den Definitionen des Wurzelbaums und
Vorgängergraphen. Zu zeigen ist aber noch, dass deren Längen höchstens d(v) betragen:
Wenn ein Verbesserungsschritt auf die Knoten u und v durchgeführt wird, so gilt direkt
danach d(v) = d(u) + w(u, v). Falls nun danach – in einem anderen Schritt – d(u) verkürzt
wird, gilt d(v) > d(u) + w(u, v) (und das Array speichert zu dem Zeitpunkt den falschen
Distanzwert für v1; Gπ enthält aber den richtigen – bisher kürzesten – Pfad). Der Fall d(v)
< d(u) + w(u, v) kann nicht auftreten, da es sonst nicht mehr die Kante (u, v) in Gπ geben
würde oder einen negativen Kreis in G. Daraus folgt für einen Pfad P = [s = πk(v), ..., π(v),
v] von s zu v in Gπ:
d(πi(v))
≥
d(πi+1(v)) + w(πi+1(v), πi(v)), für i = 0, ..., k-1
1 Bemerkung: Dieser Fall kann beim Algorithmus von Dijkstra nicht auftreten, da er die Knoten in einer bestimmten,
gewissermaßen optimalen Reihenfolge betrachtet. Eine solche optimale Reihenfolge der Distanzverbesserungen
ist nur möglich bei positiven Kantengewichten, azyklischen Graphen oder sonstigen Spezialfällen. Siehe dazu
bei Interesse [LEDA99], wo dies formal charakterisiert wird.
16
aufsummiert
⇒
d(v) = d(π0(v))
≥
d(s) +
k −1
∑ w(π
i +1
(v), π i (v)) = 0 + w(P)
i =0
Also besitzt der Weg P in Gπ Länge von höchstens d(v).
‫ڤ‬
Folgendes Lemma zeigt, dass die vom Algorithmus von Dijkstra berechnete
Distanzfunktion v die Vorraussetzungen von Lemma 3 b) erfüllt:
Lemma 5:
Sei G = (V, E, w) ein gerichteter, gewichteter Graph mit positiver (≥ 0)
Gewichtungsfunktion w.. Nach Terminierung des Algorithmus von Dijkstra, angewendet
auf diesen Graphen und einem Quellknoten s ∈ V , gilt für die zurückgegebene DistanzFunktion d: V → ℜ ∪ {−∞,+∞} :
a) d(v) ≥ δ(v) für alle v ∈ V ,
b) d(s) ≤ 0 und
c) d(v) ≤ d(u) + w(u, v) für alle e = (u, v) ∈ E
Beweis:
Zu a)
Dies zeigen wir durch Induktion über die Anzahl m der Verbesserungsschritte (siehe
eventuell Aussage des Lemmas 4):
Induktionsanfang:
Für m = 0, also wenn noch kein Verbesserungschritt durchgeführt wurde, ist d(s) = 0 und
d(v) = +∞ für v ∈ V \{s}. Dies erfüllt sicherlich die Behauptung a)
Induktionsannahme:
Die Behauptung gelte direkt nach dem (m-1). Schritt der while-Schleife.
Induktionsschritt:
Falls beim m. Schritt die Kondition des if-Teils false ergibt, ändert sich nichts an der
Distanzfunktion d und demnach ist wegen der Induktionsvoraussetzung natürlich die
Behauptung immer noch erfüllt.
Andernfalls wird d(v) = d(u) + w(u, v) gesetzt. Wegen der Induktionsannahme gibt es dann
einen Pfad von s nach u der Länge ≤ d(u). Daraus folgt dann, dass auch ein Pfad von s
nach v über u (der Länge ≤ d(v)) existiert. Dieser kann natürlich nicht kürzer als ein
kürzester Pfad von s nach v sein. Damit ist die Behauptung nach dem m.
Verbesserungschritt immer noch erfüllt.
17
Zu b)
d(v) kann im Algorithmus von Dijkstra aufgrund des dort
Verbesserungsschrittes niemals zunehmen und am Anfang gilt: d(s) = 0.
verwendeten
Zu c)
Für diesen Beweis definiere Q0 die Menge Ø und Qm die Menge Q im Algorithmus von
Dijkstra direkt nach dem m. Schritt der while-Schleife (≠ Verbesserungsschritt). Zm sei das
Komplement von Qm: Zm := Vm \ Qm. Mit vm bezeichne ich im folgenden das im m. Schritt
der while-Schleife gewählte u (mit minimalem d(u)) im Algorithmus von Dijstra
Offenbar wird für jeden Knoten v ∈ V nach dem Streichen von v aus Q der Wert d(v) nicht
mehr geändert. Hauptargument für den folgenden Induktionsbeweis ist, dass durch die
Wahl des u mit minimalem d(u) aus Q gilt (und der Tatsache, dass alle Kanten positive
Längen haben):
d(s = v1) ≤ d(v2) ≤ ... ≤ d(vn)
(*)
Behauptung: Direkt nach jedem m. Schritt der while-Schleife gilt:
d(v) ≤ d(u) + w(u, v), falls (für alle) e = (u, v) ∈ E und u, v ∈ Zm
Beweis der Behauptung durch vollständige Induktion:
Induktionsanfang:
Falls m = 0, also Zm = Ø ist die Behauptung sicherlich erfüllt.
Induktionsannahme:
Die Behauptung gelte direkt nach dem (m-1). Schritt der while-Schleife.
Induktionsschritt:
Betrachte eine Kante e = (u, v) in G mit u, v ∈ Zm:
Falls u und v beide auch in Zm-1 enthalten sind, folgt die Behauptung durch die
Induktionsannahme.
Falls u nicht in Zm-1 enthalten ist, also u = vm und v = vk mit k < m, dann folgt aus (*) d(u) ≥
d(v) und wegen positiver Kantengewichte die Behauptung.
Falls v nicht in Zm-1 enthalten ist, also v = vm und u = vk mit k < m, dann gab es im k.
Schritt der while-Schleife einen Verbesserungsschritt (siehe Aussage des Lemmas 4), in
dem d(v) := d(u) + w(u, v) gesetzt wurde, falls zu dem Zeitpunkt d(v) > d(u) + w(u, v) galt.
Also ist die Behauptung auch in diesem Fall nach Hinzufügung von vm zu Z erfüllt.
Da dem Induktionsbeweis nach die Behauptung für Zn = V gilt, ist damit diese Eigenschaft
des Algorithmus bewiesen.
‫ڤ‬
18
Der nun folgende Satz, den man ebensogut als Korollar bezeichnen könnte, zeigt die
Korrektheit des Algorithmus von Dijkstra und beendet diesen Abschnitt:
Satz 1:
Sei G = (V, E, w) ein gerichteter, gewichteter Graph mit positiver Gewichtungsfunktion w.
Nach Terminierung des Algorithmus von Dijkstra, angewendet auf diesen Graphen und
einem Quellknoten s ∈ V , gilt für die zurückgegebene Distanz-Funktion d: V →
ℜ ∪ {−∞,+∞} und die Vorgängerfunktion π: V → V ∪ {nil} und die Laufzeit:
a) d(v) = δ(v) für alle v ∈ V .
b) Der durch π induzierte Vorgängergraph Gπ = (Vπ Eπ) ist ein kürzester Wegebaum
mit Wurzel s.
c) Es gibt für den Algorithmus von Dijkstra eine O(n2) Zeit Implementierung.
Beweis:
Zu a)
Folgt direkt aus Lemma 5 und Lemma 3 b).
Zu b)
Folgt direkt aus a) und Lemma 4.
Zu c)
Bis auf das Finden von u ∈ Q mit d(u) = min({d(v) | v ∈ Q }) können wir sämtliche Arbeit
den Knoten und Kanten des Graphen G zuordnen und lässt sich demnach in O(n + m)
implementieren. Falls wir eine verkettete Liste für die Verwaltung der Menge Q
verwenden, dann kann das minimale u aus Q jeweils in Zeit O(|Q|) gefunden werden. Die
Funktionen d und π würde man mit Hilfe eines Arrays implementieren, so dass man in
konstanter Zeit darauf zugreifen kann. Insgesamt ergibt das dann eine O(n2)
Implementierung.
‫ڤ‬
Die Laufzeit von O(n2) lässt sich durch die Verwendung von komplizierteren
Datenstrukturen zur Verwaltung der Menge Q noch verbessern. So kommt man mit einer
Priority-Queue auf eine Laufzeit von O((n + m) log n) (siehe [BLUM98], S. 246), was für
lichte Graphen effizienter als O(n2) sein kann. In [BRAN94] wird auf weitere Autoren
verwiesen, welche mit Hilfe von Fibonacci-heaps bzw. AF-heaps die Zeitschranke von
n log n
) für den Algorithmus von Dijkstra erreicht haben.
O( m +
log log n
19
2.2.3 Im Detail: Algorithmus von Floyd
Der Algorithmus von Floyd löst das Alle-Paare-kürzeste-Weg-Problem für Graphen G =
(V, E, w) mit V = {1, ..., n} durch dynamische Programmierung. Dazu gibt er zwei
Matrizen zurück: Die Floyd-Distanz-Matrix D und die Floyd-Wege-Matrix Π (diese
Matrizen werde ich im Folgenden zum Teil auch verkürzt als Distanz-Matrix bzw. WegeMatrix bezeichnen) zurück. Die erste enthält alle kürzesten Distanzen und die zweite
Matrix Π speichert alle kürzesten Wege auf folgende, sehr komprimierte Art und Weise:
Der Matrix-Eintrag πij speichert den direkten Vorgänger von j auf dem bzw. einem
kürzesten Pfad von i nach j. Folgender Pseudocode ist – zumindest, was die Art der WegeMatrix Π betrifft – die wohl gängigste Variante:
Algorithmus: FLOYD (basiert am meisten auf [BLUM98], S. 250)
Eingabe: gerichteter, gewichteter Graph G = (V, E, w) mit (o.B.d.A.) V = {1, ..., n}
Ausgabe: entweder eine n x n - Matrix D mit dij = δ (i, j ) für alle i, j ∈ V und
eine n x n - Matrix Π mit πij = (der letzte Knoten k vor j auf einem
kürzesten Pfad von i nach j) für alle i, j ∈ V
oder die Meldung „Es existiert Kreis mit negativem Gewicht in G“
Methode:
// Initialisiere die kürzeste-Distanz-Matrix D und die kürzeste-Weg-Matrix Π, falls
// nicht schon getan
for i := 1 to n
do
for j := 1 to n
do
⎧w(i, j ), falls (i, j ) ∈ E
⎪
d ij := ⎨0, falls i = j
⎪∞, sonst
⎩
⎧nil , falls i = j oder wij = ∞
π ij := ⎨
⎩i, sonst
od
od
// Eigentlicher Algorithmus
for k := 1 to n
(*)
do
for i := 1 to n
do
for j := 1 to n
do
if d ij > d ik + d kj
20
then
d ij := d ik + d kj ;
πij := πkj ;1
fi
od
od
od
if ( d ii < 0 für ein i∈{1, ..., n})
then
print(“Es existiert ein negativer Kreis im Graphen“);
stop;
fi
return D, Π;
‫ڤ‬
Bevor wir die Korrektheit des Algorithmus von Floyd zeigen, betrachten wir ein Beispiel:
dij
0
1
2
3
4
5
6
7
8
9
0
0
1
2
4
5
6
4
7
6
3
1
1
0
1
3
4
5
3
6
5
2
2
2
1
0
2
3
4
2
5
4
1
3
4
3
2
0
1
2
4
7
6
3
4
5
4
3
1
0
1
5
8
6
3
5
5
4
3
2
1
0
5
8
5
2
6
4
3
2
4
5
6
0
3
6
3
7
7
6
5
7
8
9
3
0
3
6
8
6
5
4
6
7
8
6
3
0
3
πij
0
1
2
3
4
5
6
7
8
9
9
3
2
1
3
4
5
3
6
3
0
0
1
1
1
1
1
1
1
1
1
1
0
2
2
2
2
2
2
2
2
2
1
1
3
3
3
6
6
9
9
3
2
2
2
4
4
2
2
2
2
4
3
3
3
3
5
3
3
5
5
5
9
9
9
4
4
9
9
9
9
6
2
2
2
2
2
2
7
7
2
7
6
6
6
6
6
6
6
8
6
8
9
9
9
9
9
9
7
7
9
9
2
2
2
2
2
2
2
2
8
-
Tab. 1: Anwendung von Floyd auf Beispiel-Graph 2 (Abb. 2). Die vom Algorithmus von Floyd
zurückgegebenen Matrizen D und Π bei Eingabe von Beispiel-Graph 2 (Abb. 2). Hierbei
bedeutet in der Matrix Π ´-´ nil.
Die Korrektheit des obigen Algorithmus lässt sich meiner Meinung nach am einfachesten
dadurch zeigen, indem man die Korrektheit einer leicht veränderten Version FLOYD’ des
Algorithmus zeigt und dann begründet, warum der Korrektheitsbeweis von FLOYD’ auch
auf FLOYD zutrifft. Die Version FLOYD’ unterscheided sich von FLOYD nur darin, dass sie
für jeden Schritt k der äußersten while-Schleife explizit neue Matrizen Dk und Πk aus den
1 An dieser Stelle sind auch andere (sinnvolle) Zuweisungen möglich. Damit befasst sich der Kern der Diplomarbeit.
Siehe Kap. 4
21
Matrizen Dk-1 und Πk-1 des vorherigen Schrittes berechnet anstatt einfach die alten Werte
durch neue zu überschreiben.
Algorithmus: FLOYD’
Eingabe: gerichteter, gewichteter Graph G = (V, E, w) mit (o.B.d.A.) V = {1, ..., n}
Ausgabe: entweder eine n x n - Matrix Dn mit d ijn = δ (i, j ) für alle i, j ∈ V und
eine n x n - Matrix Πn mit π ijn = (der letzte Knoten k vor j auf einem
kürzesten Pfad von i nach j) für alle i, j ∈ V
oder die Meldung „Es existiert Kreis mit negativem Gewicht in G“
Methode:
// Initialisiere die kürzeste-Distanz-Matrix D und die kürzeste-Weg-Matrix Π, falls
// nicht schon getan
for i := 1 to n
do
for j := 1 to n
do
⎧w(i, j ), falls (i, j ) ∈ E
⎪
0
d ij := ⎨0, falls i = j
⎪∞, sonst
⎩
⎧nil , falls i = j oder wij = ∞
π ij0 := ⎨
⎩i, sonst
od
od
// Eigentlicher Algorithmus
for k := 1 to n
(*)
do
for i := 1 to n
do
for j := 1 to n
do
if d ijk −1 > d ikk −1 + d kjk −1
then
d ijk := d ikk −1 + d kjk −1 ;
π ijk := π kjk −1 ;1
else
d ijk := d ijk −1 ;
1 An dieser Stelle sind auch andere (sinnvolle) Zuweisungen möglich. Damit befasst sich der Kern der Diplomarbeit.
Siehe Kap. 4
22
π ijk := π ijk −1 ;
fi
od
od
od
if ( d iin < 0 für ein i∈{1, ..., n})
then
print(“Es existiert ein negativer Kreis im Graphen“);
stop;
fi
return Dn, Πn;
‫ڤ‬
Für die Korrektheit von FLOYD’ brauchen wir noch eine Definition:
⎧inf({w( P) | P ist (endlicher ) Pfad von v nach w, der als innere Knoten nur Knoten
⎪
aus {v1 ,..., v k } enthält}), falls ein solcher Pfad existiert ,
δ := ⎨
⎪+ ∞, sonst
⎩
k
ij
Aus der Definition von δ ijk folgt direkt, dass δ ijk ≥ δ ij := δ(i, j) für k ≤ n und δ ijn = δ ij .
Wenn man nun zeigen könnte, dass δ ijk = d ijk für alle k, dann hätte man damit zum großen
Teil schon die Korrektheit des Algorithmus von Floyd gezeigt (zumindest beim Fehlen
von negativen Kreisen). Dies wollen wir nun im folgenden Lemma machen:
Lemma 6:
Sei G = (V, E, w) ein gerichteter, gewichteter Graph. G enthalte keine negativen Kreise.
Dann gilt nach Terminierung von FLOYD’, angewendet auf diesen Graphen, für alle k
folgendes:
a) δ ijk = d ijk
b) π ijk enthält als Wert den letzten Knoten vor j auf einem Pfad P von i nach j in G
der Länge δ ijk (also P = [i, ..., k, j]), falls j von i aus erreichbar und sonst π ijk = nil
Beweis:
Beweis der Behauptungen a) und b) durch vollständige Induktion über k:
Induktionsanfang:
Bei k = 0 sind sicherlich beide Behauptungen a) und b) erfüllt
23
Induktionsannahme:
Die Behauptungen a) und b) gelten für k = l – 1
Induktionsschritt:
Ein kürzester Pfad von Knoten i nach j mit inneren Knoten ∈ {1, ..., k} enthält entweder
den Knoten k gar nicht als inneren Knoten oder genau einmal.
Im ersten Fall gilt dann δ ijk −1 = δ ijk . Gemäß Induktionsvoraussetzung wurde dieser kürzeste
Pfad schon im Schritt k-1 betrachtet. Daraus folgt d ijk −1 ≤ d ikk −1 + d kjk −1 und dementsprechend
gilt nach der Zuweisung im k. Schritt
d ijk −1 = d ijk und π ijk −1 = π ijk , was die beiden
Behauptungen zeigt.
Im zweiten Fall, also wenn δ ijk −1 > δ ijk , setzt sich dieser kürzester Pfad aus einem kürzesten
(Teil-) Pfad P1 von 1 zu k und einem kürzesten (Teil-) Pfad P2 von k zu j zusammen
(Lemma 1), wobei alle inneren Knoten von P1 und P2 aus {1, ..., k} sind. Also gilt δ ijk =
δ ikk −1 + δ kjk −1 . Nach Induktionsvoraussetzung wurden diese Teilpfade schon im Schritt k-1
betrachtet und es folgt d ijk −1 > d ikk −1 + d kjk −1 . Also werden im k. Schritt der äußeren whileSchleife die Zuweisungen d ijk := d ikk −1 + d kjk −1 und π ijk := π kjk −1 durchgeführt, welche
offensichtlich korrekt sind.
Zum Induktionsbeweis ist vielleicht noch zu bemerken, dass - wie unschwer zu sehen - ein
einmal in eine Matrix geschriebener Wert niemals verändert wird.
‫ڤ‬
Jetzt ist noch zu zeigen, dass FLOYD’ bei Existenz von negativen Kreisen in G wie
gewünscht mit der Meldung „Es existiert ein negativer Kreis im Graphen“ abbricht:
Lemma 7:
Sei G = (V, E, w) ein gerichteter, gewichteter Graph. Falls G einen negativen Kreis
enthält, dann gibt FLOYD’ die Meldung „Es existiert ein negativer Kreis im Graphen“
aus.
Beweis:
Betrachte einen einfachen negativen Kreis K = {v1, v2, ..., vq, ..., vr, v1}. Hierbei sei vq der
Größte der inneren Knoten v2, ..., vr von K. Nach Lemma 6 und der Wahl von q sind zu
irgendeinem Zeitpunkt k = k’ < q die Distanzen d vk1 ,vq und d vkq ,v1 berechnet. Zum Zeitpunkt
k = vq wird dann wegen der Zuweisung d vk1v1 := d vk1−,v1q + d vkq−,1v1 spätestens d vk1v1 < 0 gelten und
höchstens noch kleiner werden. Am Ende wird dann die Meldung „Es existiert ein
negativer Kreis im Graphen“ ausgegeben.
24
‫ڤ‬
Die letzen beiden Lemmata zusammen mit einer trivialen Performanzanalyse ergeben dann
direkt folgendes Lemma über die Korrektheit von FLOYD’:
Lemma 8:
Sei G = (V, E, w) ein gerichteter, gewichteter Graph mit V = {1, ..., n} und einer
Kostenfunktion w: E → ℜ . Falls G einen negativen Kreis enthält, dann termininiert der
Algorithmus FLOYD’ mit der Meldung „Es existiert ein negativer Kreis im Graphen“.
Ansonsten gibt er eine Matrix D zurück mit dij = δ(i, j) für alle i, j und eine Matrix Π mit πij
= kij, für alle i, j, wobei kij der letzte Knoten vor j auf einem kürzesten Pfad von i nach j sei
(also sehe ein solcher kürzester Pfad von i nach j so aus: [i, ..., kij, j]). Dies macht der
Algorithmus in Θ(n3) Zeit.
‫ڤ‬
Jetzt ist noch zu zeigen, dass die Lemmata 6, 7 bzw. 8 auch für Algorithmus FLOYD
gelten. Hierfür brauchen wir noch zur einfacheren oder eindeutigeren Formulierung eine
neue Definition: Es bezeichne d ij (k) den Wert von dij bzw. D(k) die Matrix D im
Algorithmus FLOYD direkt nach dem k. Schritt der äußersten for-Schleife (*).
Lemma 9:
Für die Algorithmen FLOYD und FLOYD’ gilt: Für alle k ≤ n gilt: Direkt nach jedem k.
Durchlauf der äußersten for-Schleife (*) der Algorithmen sind die Matrizen D und Π von
FLOYD gleich den Matrizen Dk und Πk von FLOYD’, also Dk = D(k).
Beweis:
Induktionsanfang:
Bei k = 0 ist sicherlich D0 = D(0).
Induktionsannahme:
Die Behauptung gelte für k = l – 1
Induktionsschritt:
Ich zeige nun, dass bei k = l für alle i, j bei der if-Bedingung d ij > d ik + d kj des
Algorithmus FLOYD folgendes gilt: dik = d ikk −1 und dkj = d kjk −1 :
Damit dik < d ikk −1 gelten kann, muss nach der Induktionsannahme zuvor im k. Schritt die ifBedingung d ik > d ik + d kk gegolten haben. Dies ist aber nicht möglich.
Analoges gilt für dkj. Da offensichtlich auch in jedem Schritt der äußersten Schleife jeder
Eintrag der Matrizen nur genau einmal beschrieben wird, ist damit die Behauptung
gezeigt.
25
‫ڤ‬
Aus den Lemmata 8 und 9 folgt dann direkt der abschließende Satz dieses Kapitels:
Satz 2:
Sei G = (V, E, w) ein gerichteter, gewichteter Graph mit V = {1, ..., n} und einer
Kostenfunktion w: E → ℜ . Falls G einen negativen Kreis enthält, dann termininiert der
Algorithmus von Floyd FLOYD mit der Meldung „Es existiert ein negativer Kreis im
Graphen“. Ansonsten gibt er eine Matrix D zurück mit dij = δ(i, j) für alle i, j und eine
Matrix Π mit πij = kij, für alle i, j, wobei kij der letzte Knoten vor j auf einem kürzesten
Pfad von i nach j sei (also sehe ein solcher kürzester Pfad von i nach j so aus: [i, ..., kij, j]).
Dies macht der Algorithmus in Θ(n3) Zeit.
‫ڤ‬
26
3
Kürzeste Wege in Straßennetzen
In diesem Kapitel geht es um die (automatisierte) Routenplanung in Straßennetzen. Dazu
definieren wir zuerst formal ein Straßennetz zum Zwecke der Routenplanung. Danach
betrachten wir ein wenig den Prozess der Modellierung eines Straßennetzes aus der
Realität mit unserer Definition. Zuletzt gehen wir auf kürzeste Wege in solchen
Straßennetzen ein und insbesondere auf Unterschiede und Gemeinsamkeiten zu den
kürzeste-Weg-Problemen bzw. Lösungsmöglichkeiten in „normalen“ Graphen, wie wir sie
im vorherigen Kapitel kennen gelernt haben.
In diesem Kapitel, wie in den folgenden, habe ich nur ein wenig von [HASS00] als
Literatur benutzt und sonst das Wissen aus bisherigen Informatik-Vorlesungen, die aber
nichts direkt mit dieser Thematik zu tun hatten. Und natürlich stand Prof. Plümer mit Rat
und Tat zur Seite. Insofern sind die Definitionen, die Prof. Plümer bisher auch nur zum
kleinen Teil gesehen hat, vielleicht mit etwas Vorsicht zu genießen, weil ich nicht weiß,
ob und eventuell wie diese schon mal definiert wurden.
3.1 Einleitung und Definitionen
Ein Straßennetz ist für uns eine bestimmte Erweiterung eines gerichteten, gewichteten
Graphen G = (V, E, w). Formal definieren wir Straßennetz wie folgt: Ein Straßennetz ist
ein Tupel (V, E, S, T, w, s, t), wobei
•
V, E, w wie bei einem gewichteten, gerichteten Graphen mit positiver
Kostenfunktion die Knotenmenge V, Kantenmenge E ⊆ (V × V ) \ {(v, v) | v ∈ V }
bzw. Kostenfunktion w: E → ℜ + . Hierbei gelte wieder |V| = n, |E| = m,
•
S die Menge der Straßen ist,
•
T die Menge der Straßentypen (z.B. Autobahnen, Bundestraßen, Landstraßen, ...)
ist,
•
s: E → S eine Funktion der Kanten auf die Straßen ist, welche also die Kanten
den jeweiligen Straßen zuordnet,
•
t: S → T eine Funktion der Straßen auf die Straßentypen ist, die also besagt, was
für einem Straßentyp die Straßen jeweils angehören.
Zu dieser Definition ist zu bemerken, dass hierdurch Straßennetze möglich sind, wie sie in
der realen Welt nicht vorzufinden sind. So ist es mit der Definition beispielsweise
möglich, Straßen zu konstruieren, die aus vielen einzelnen Stücken bestehen, die nicht
zusammenhängend sind. Durch Hinzufügen einiger zusätzlicher Bedingungen /
Constraints in der Definition könnte man dies (ohne großen Aufwand) vermeiden. Da aber
keine der folgenden Definitionen, Algorithmen oder sonstige Überlegungen solche
zusätzlichen Eigenschaften des Straßennetz-Graphen benötigen, belassen wir es bei der
27
einfacheren. Außerdem kann es ja auch sein, dass man in einem dynamischeren Kontext
ein Straßennetz modellieren möchte, in dem z.B. ein Straßenstück einer Straße wegen
einer Baustelle fehlt.
In den folgenden Kapiteln werden wir manchmal noch zusätzlich von dem Straßennetz
fordern, dass es zusammenhängend ist oder dass es maximal einen kürzesten Weg
zwischen zwei verschiedenen Knoten gibt. Erstere Forderung vereinfacht die Algorithmen
und Erklärungen, und es ist nicht schwer zu sehen, dass diese die jeweiligen Probleme an
sich nicht (asymptotisch) vereinfachen. Die zweite Forderung vereinfacht z.T. das Problem
an sich, ist aber in der Realität wie die erste auch (fast) immer erfüllt, zumindest wenn
man die Kostenfunktion unter anderem von der geometrischen Länge des Weges oder der
Fahrzeit abhängig macht.
3.2 Modellierung eines realen Straßennetzes
In diesem Abschnitt geht es darum, wie man ein reales Straßennetz (z.B. das Straßennetz
von Nordrhein-Westfalen) in (V, E, S, T, w, s, t) umformen bzw. in einen Computer
eingeben kann, um darauf Algorithmen zur Routenplanung für die Realität ablaufen zu
lassen. Dies erscheint auf den ersten Blick trivial – man nehme einfach als die Knoten die
Kreuzungspunkte von Straßen und als die Kanten die Straßenstücke zwischen den
Kreuzungspunkten, messe Zeiten, Längen oder nehme sonstige Kostenfunktionen etc. –
und ist auch nicht allzu schwierig, hat aber doch ein paar mögliche Fallstricke und
verdient ein wenig Beachtung.
3.2.1 Granularität
Bei der Modellierung eines Straßennetzes aus der Realität mit der Straßennetz-Definition
aus dem vorherigen Abschnitt gibt es einige Freiheitsgrade. Einen von diesen würde ich
als die Granularität der Modellierung bezeichnen1. Darunter verstehen wir, wieviele (für
uns relevante) atomare Objekte des Straßennetzes in der Realität zu jeweils einem
modellierten Objekt zusammengefasst werden bzw. welche „Größe“ unsere Knoten und
Kanten im Straßennetz (V, E, S, T, w, s, t) haben. Für uns relevante (d.h. für die
Wegfindung relevante) atomare Objekte des zugrundeliegenden Straßennetzes in der
Realität sind einzelne Straßenspuren und Knoten auf Straßenspuren. Eine Kante im
Straßennetz-Graphen kann z.B. für eine Fahrspur einer Autobahn stehen oder kann auch
1 Die Bezeichnung „Granularität“ in diesem Kontext für das, was ich meine, stammt von mir und ich konnte nicht
herausfinden, ob es dafür nicht schon einen anderen Begriff gibt. Diese Bezeichnung dürfte aber relativ intuitiv
sein. Hierbei ist vielleicht zu bemerken, um Missverständnissen vorzubeugen, dass bei hoher Granularität die
Granulate klein sind und bei niedriger Granularität die Granulate groß sind (ähnlich wie z.B. beim Maßstab).
28
alle drei Spuren für ein bestimmtes Stück repräsentieren. In Abb. 4 ist als Beispiel eine
Kreuzung einmal in hoher Granularität und in niedriger Granularität modelliert 1.
Abb. 4: Kreuzung mit Modellierung in niedriger und hoher Granularität. Eine ziemlich komplexe
Kreuzung (mit Ampeln, die für uns keine Rolle spielen und daher auch nicht abgebildet sind),
bei der man von jeder Richtung aus kommend in jede andere Richtung fahren kann. Die
Kreuzung selbst, wie sie in der realen Welt vorkommt, ist in den Farben grau und weiß
eingezeichnet. Darüber ist in den Farben Himmelblau und Türkis eine Modellierung in
niedriger Granularität, bestehend aus nur einem (bzw. 5) Knoten und 4 Kanten angedeutet. In
den Farben rot und einem hellen orange-Ton ist eine Modellierung in hoher Granularität,
bestehend aus 28 (bzw. 32) Knoten und 40 Kanten, abgebildet.
Gerade bei der Verwendung einer niedrigen Granularität muss man aufpassen, dass im
Modell immer noch die gleichen Wege (also nicht mehr und auch nicht weniger) möglich
sind wie in der Grundlage2. Siehe dazu auch Punkt 3.2.3.
1 Zu Abb. 4 und ein paar nachfolgenden Abbildungen ist eventuell zu bemerken, dass wir keine Einbettungen von
Graphen bzw. dem Straßennetz in die Ebene betrachten. Die Graphen bzw. Straßennetze sind nur zur
Anschaulichkeit über dem Straßennetz aus der realen Welt gezeichnet.
2 Streng genommen ist die Modellierung in niedriger Granularität in Abb. 4 auch nicht absolut korrekt, da es darin
möglich ist, in der Kreuzung einen U-Turn zu machen, was in der Realität wahrscheinlich nicht möglich ist bei
normalem Verkehr und Einhaltung der Verkehrsregeln. Bei kürzeste-Weg-Berechnungen, mit denen wir uns im
folgenden hauptsächlich beschäftigen werden, dürfte diese spezielle Unkorrektheit aber meistens nicht schaden,
weil ein U-Turn eher selten in kürzesten Wegen enthalten ist (U-Turns sind eher a-posteriori Notlösungen bei
zuvor fehlerhafter Routenplanung)
29
Für viele Anwendungen wird wahrscheinlich eine eher niedrige Granularität ausreichen,
da diese meistens dazu dienen, einem Menschen zu sagen, wo er herfahren soll und
Menschen – zumindest mit ein bißchen Erfahrung – mit einer Beschreibung wie „Fahr so
lange geradeaus bis du auf die A3 auffahren kannst, dann Abfahrt Siebengebirge auf der
A3, dann rechts auf die Straße ...“ zurechtkommen. Wenn man dagegen ein
Navigationssystem für ein vom Computer gesteuertes Auto schreiben wollte, könnte man
der Steuerungs-KI mit einem gespeicherten Straßennetz hoher Granularität schon helfen.
Stausimulationen und computergestützte Straßennetz-Planung wären ebenfalls
Anwendungen für hohe Granularität. Wenn man die Wahl hat, versucht man natürlich eine
so niedrige Granularität wie möglich zu verwenden, da dies Speicherplatz einspart und
auch Laufzeit bei kürzeste-Weg-Berechnungen.
3.2.2 Redundanz
Unter Redundanz verstehe ich das Vorhandensein von Knoten im echten Inneren von
Pfaden, die eigentlich unnötig sind, weil durch diese Knoten im Prinzip nur ein Pfad geht.
In insgesamt ungerichteten Straßennetzen sind das Knoten mit einem Grad von genau
zwei. In gerichteten Straßennetzen ist dies ein wenig komplizierter1. Diese Knoten
bezeichnen wir als redundante Knoten. Siehe Abb. 5 für ein Beispiel.
Offensichtlich hat Redundanz viel mit Granularität zu tun. So gibt es in Abb. 4 bei der
Modellierung mit hoher Granularität auch den einen oder anderen redundanten Knoten
nach dieser Definition. Wenn man alle redundanten Knoten der Reihe nach entfernt (und
die Kanten entsprechend „umleitet“), erhält man eine Modellierung in niedrigerer
Granularität 2. Trotzdem machen alle Knoten der Modellierung in hoher Granularität in
dieser Kreuzung irgendwie Sinn für spezielle Anwendungen, die Straßennetze in hoher
Granularität benötigen. Z.B. weil die redundanten Knoten (als einzige Knoten)
Straßenspuren repräsentieren oder Punkte, bei denen man auf das Grün-Werden von
Ampeln oder das Vorbeifahren von anderen Verkehrteilnehmern warten muss.
Folglich definieren wir mit echter Redundanz das Vorhandensein von redundanten
Knoten, die für die betrachtete Anwendung „wirklich“ überflüssig sind3. Diese echte
Redundanz gilt es natürlich (per Definition) immer zu vermeiden, da man so Speicherplatz
und Laufzeit für Berechnungen auf dem Straßennetz einspart.
1 In gerichteten Straßennetzen (so wie wir sie in dieser Diplomarbeit ja auch eigentlich nur betrachten) ist Knoten v
genau dann redundant, wenn er genau zwei adjazente Knoten u und w hat und der Ausgangsgrad von v dem
Eingangsgrad von v entspricht.
2 So ähnlich würde man wohl Algorithmen programmieren, die ein Straßennetz von einer niedrigen Granularität in eines
mit einer höheren (der höchsten) Granularität transformieren.
3 Mir ist bewusst, dass dies keine eindeutige und klare Definition ist. Ich habe aber trotz längerem Nachdenken nichts
besseres gefunden und denke, dass das ohne weitere Formalitäten (z.B. formale Klassifikationen von
Anwendungen für Straßennetze) auch schwierig sein dürfte.
30
Abb. 5: Redundanz. Hier ist ein in den Farben grau und weiß gezeichneter Teil eines Straßennetzes zu
sehen (so wie es in der realen Welt oder in Lego aussieht). Darüber ist in den Farben
Himmelblau, Rot und einem hellen Orange-Ton eine Modellierung eingezeichnet. Die roten
Knoten sind hierbei redundant und könnten weggelassen werden (und die zu diesen Knoten
inzidenten Kanten verschmolzen werden).
3.2.3 Korrektheit der Modellierung
Die Abbildung eines realen Straßennetzes auf unsere Definition sollte (natürlich) korrekt
sein, d.h. in dem Modell (V, E, S, T, w, s, t) für ein reales Straßennetz dürfen keine Pfade
enthalten sein, die es in der Realität nicht gibt und umgekehrt. Dies ist durch
Verkehrsregeln wie Wendeverbote (diese sind oftmals eher implizit wegen starkem
Verkehrsaufkommen etc.) und Abbiegeverbote oft nur durch zusätzliche Knoten (und
Kanten) machbar. Gerade bei der Wahl einer niedrigen Granularität der Modellierung
muss man darauf achten, dass die Korrektheit gewährleistet bleibt.
Es ist klar, dass man bei der Routenplanung nicht auf die Korrektheit verzichten kann1.
1 Höchstens könnte man sie auf kürzeste Pfade einschränken,, obwohl es hier wahrscheinlich die bessere Alternative
wäre, alle Kanten, die in keinem kürzesten Pfad vorkommen, einfach wegzulassen.
31
3.2.4 Kantenkosten
Wie soll man die Kantenkosten wählen? Generell sind beliebige Kostenfunktionen erlaubt
und je nach Anwendung auch sinnvoll: Fahrzeit, geometrische Distanz, Benzinkosten,
Straßenbefahrungskosten, Zölle, ... und Kombinationen. Wenn man nach einem Weg von
Punkt A nach Punkt B sucht, dann interessiert einem meistens die Zeitdauer der Reise von
A nach B. Daher werden wir mit dem Kantenkosten immer – mehr oder weniger explizit –
die Zeitdauer meinen 1. Die einfacher zu bestimmende geometrische Länge des Weges ist
eigentlich nur sekundär als Approximation für die Zeitdauer interessant (auch wenn sie bei
der zwischenmenschlichen Kommunikation wichtiger zu sein scheint). Deshalb werden
wir für die Kantenkosten irgendwie die Zeitdauer des Befahrens der entsprechenden Kante
nehmen.
Wie soll die Zeitdauer bestimmt werden? Sinnvolle Beispiele für die Wahl der
Kantenkosten sind die in der Realität gemessene durchschnittliche Fahrzeit über die Kante
(vom Startknoten der Kante zum Zielknoten). Oder eine Approximation der Zeitdauer,
indem man die geometrische Länge durch die vom Gesetzgeber für diese Kante erlaubte
Höchstgeschwindigkeit teilt. Diese durchschnittlichen oder approximierten Kosten im
Modell können natürlich wegen der fehlenden Berücksichtigung von Stau, Ampeln,
Vorfahrtsregeln etc. sehr von den Kosten in der Realität abweichen, was sich durch eine
Modellierung, wie wir sie verwenden (keine Ampel-Daten, keine dynamischen Daten vom
Verkehr vorliegend etc.) aber auch nicht vermeiden lässt.
3.3 Kürzeste Wege
Dadurch, dass ein Straßennetz N = (V, E, S, T, w, s, t) ja in erster Linie ein Graph ist,
lassen sich für diese – und so machen wir das auch – die gleichen Definitionen bzgl.
kürzester Wege verwenden wie bei Graphen. So bezeichnen wir z.B. im Folgenden auch in
Straßennetzen N mit δ(i, j) (oder um den Bezug zum jeweiligen Straßennetz / Graph
klarzumachen mit δN(i, j) ) die (kürzeste) Distanz zwischen den Knoten i und j aus N.
Dementsprechend lassen sich die gleichen Algorithmen zur Berechnung kürzester Wege
wie die in Kapitel zwei angesprochenen verwenden, indem man einfach S, T, s und t
ignoriert. Dass in Straßennetzen keine negativen Kanten vorkommen, vereinfacht das
Ganze noch.
Die in Kapitel zwei angesprochenen Algorithmen sind zum Teil schon sehr effizient und
optimal von den Laufzeiten oder Speicherplatzbedürfnissen. Deshalb ist es nicht
unmittelbar klar, ob es überhaupt „Sinn“ macht, sich Gedanken über weitere Algorithmen
1 Den Algorithmen und Datenstrukturen, die wir später zur Berechnung kürzester Wege herleiten, ist es natürlich „egal“,
was die Funktion w von (V, E, S, T, w, s, t) in der Realität bedeutet.
32
oder vor allen Dingen Heuristiken, die dann nicht immer die wirklich kürzesten Wege
ausgeben, zu machen. Es gibt aber, gerade bei der Routenplanung in realen Straßennetzen,
Anwendungen, für die z.B. der Algorithmus von Dijkstra von der Laufzeit her zu
ineffizient ist oder die Speicherung einer Floyd-Wege-Matrix zu viel Speicherplatz
benötigt.
Stephan Hasselberg nennt zu diesem Punkt in seiner Dissertation (siehe [HASS00], S. 4 f.)
Verkehrsfluss-Simulationen als Beispiel. In diesen Simulationen wird der Verkehrsfluss in
einem Straßennetz simuliert zum Zwecke der Grundlagenforschung und insbesondere um
Verkehrsnetze in einem dynamischen Kontext mit Ampeln, wirklichen
Verkehrteilnehmern etc. optimieren zu können. Bei diesen Simulationen wird eine Menge
von Verkehrsteilnehmern z.T. individuell mit ihrem jeweiligen Verhalten simuliert. Eine
solche Testsimulation für das – noch vergleichsweise kleine – Straßennetz der Stadt
Wuppertal benötigte ca. 9000 Knoten und 17000 Kanten. In jedem Schritt dieser
Simulation müssen im Worst-Case 500000 kürzeste-Weg-Berechnungen durchgeführt
werden, welche auf den benutzten State-of-the-Art (zu dem Zeitpunkt) Workstations
mehrere Stunden Zeit benötigten.
33
4
Variante der Floyd-Wege-Matrix für Straßennetze
In Abschnitt 2.2.3 haben wir den Algorithmus von Floyd kennengelernt, welcher in O(n3)
Zeit das alle-Paare-kürzeste-Weg-Problem löst. Dieser gibt zwei Matrizen D und Π
zurück, welche in komprimierter Form die kürzesten Distanzen δ zwischen allen Knoten
bzw. die kürzesten Wege speichern. Wenn nun viele Weganfragen für ein Straßennetz zu
beantworten sind (wahrscheinlich dann auch über einen längeren Zeitraum), dann muss
man natürlich nicht jedes Mal die Matrizen D und Π neu berechnen, sondern kann diese
immer wieder benutzen (zumindest solange sich das Sraßennetz nicht ändert). So kann
man dann, nachdem man einmal die Preprocessing-Zeit von Θ(n3) für die Berechnung von
D und Π investiert und dauerhaft Θ(n2) Speicherplatz für diese reserviert hält, in jeweils
Θ(|P|) = O(n) Zeit einen kürzesten Pfad P ermitteln bzw. in O(1) eine kürzeste Distanz.
Inhalt dieses Kapitels und ein Schwerpunkt der Diplomarbeit ist es nun, die Θ(|P|) Zeit für
eine kürzeste-Weg-Berechnung mit Hilfe von Π für bestimmte Anfragen noch zu
verbessern.
Dazu nehmen wir in Abschnitt 4.1 noch einmal die Floyd-Wege-Matrix, wie wir sie in
Abschnitt 2.2.3 kennengelernt haben, unter die Lupe und untersuchen, ob sie die einzige
derartige Möglichkeit zur Speicherung kürzester Wege eines Graphen / Straßennetzes ist.
Im darauf folgenden Abschnitt leiten wir eine Definition für eine bestimmte Variante der
Floyd-Wege-Matrix her, welche die für unsere Zwecke optimale Struktur hat. Abschnitt
4.3 beschreibt dann einen Algorithmus, welcher eine normale Floyd-Wege-Matrix in die in
Abschnitt 4.2 definierte Variante transformiert.
Die Idee zu der Variante der Floyd-Wege-Matrix stammt von Prof. Plümer. Sonstige
Literatur wurde nicht benutzt.
4.1 Die Floyd-Wege-Matrix genauer betrachtet
Im ganzen Kapitel 4 sei (V, E, S, T, w, s, t) das zugrundeliegende Straßennetz.
Schauen wir uns nochmal an, wie wir kürzeste Wege in der Floyd-Wege-Matrix – so wie
sie in Kapitel 2.2.3 vorgestellt wurde – gespeichert werden (Tab. 2).
Ist dies die einzige Möglichkeit, alle kürzesten Wege in einer Matrix zu speichern? Nein,
denn wenn man im Algorithmus FLOYD die Anweisung „πij := πkj;” durch “πij := πik”
ersetzt und im Initialisierungsteil πij := j statt πij := i, falls wij < ∞ und i ≠ j, dann wird bei
einem Matrix-Eintrag πij nicht der letzte Knoten vor j auf einem kürzesten Pfad von i nach
j gespeichert, sondern der erste nach i. Siehe dazu Tab. 3.
34
πij
0
1
2
3
4
5
6
7
8
9
0
-
1
0
-
2
1
1
-
3
4
5
6
2
7
6
8
9
2
-
6
-
Tab. 2: Floyd-Wege-Matrix für einen Pfad von 0 nach 7. Diese Matrix ist die gleiche wie die aus
Tab. 1, nur der Einfachheit halber auf die den kürzesten Pfad P = [0, 1, 2, 6, 7] betreffenden
Einträge beschränkt.
πij
0
1
2
3
4
5
6
7
8
9
0
-
1
1
-
2
3
4
5
2
-
6
6
7
1
2
6
8
9
-
7
-
Tab. 3: Eine Variante der Floyd-Wege-Matrix für einen Pfad von 0 nach 7. Diese Matrix speichert
den gleichen kürzesten Pfad P = [0, 1, 2, 6, 7] wie die in Tab.2, nur auf eine andere Weise.
Man kann sich leicht überlegen, dass man im Algorithmus FLOYD die Anweisung „πij :=
πkj;” durch die allgemeinere “πij := (ein Knoten echt innerhalb des gerade betrachteten
momentan kürzesten Pfades von i nach j über k)” ersetzen kann, welche die beiden obigen
als Spezialfälle beinhaltet. Dann bedeutet ein Matrix-Eintrag πij = k, dass der in der Matrix
gespeicherte kürzeste Pfad von i nach j irgendwie über den Knoten k geht. Falls der
kürzeste Weg von i nach j über nur genau eine Kante geht, würde man wohl πij = i oder πij
= j (oder irgendetwas eindeutiges Anderes) setzen bzw. definieren. Betrachten wir als
Beispiel folgende Matrix (Tab. 4):
35
πij
0
1
2
3
4
5
6
7
8
9
0
-
1
0
-
2
1
1
-
3
4
5
6
7
2
2
6
-
6
-
8
9
-
-
Tab. 4: Eine weitere Variante der Floyd-Wege-Matrix für einen Pfad von 0 nach 7. Diese Matrix
speichert den gleichen kürzesten Pfad P = [0, 1, 2, 6, 7] wie die in Tab.2 und 3, nur auf eine
andere Weise.
Die in einer solchen Matrix Π gespeicherten Wege lassen sich durch folgende Art von
Baum gut veranschaulichen: Ein geordneter Binärbaum T heißt Matrix-Wegbaum für einen
Pfad von u nach v bzgl. Matrix Π oder, kürzer geschrieben, (Π, u, v)-Wegbaum gdw. eine
der folgenden Bedingungen zutrifft 1:
•
T besteht nur aus einem Blatt, das mit „u – v, u“ oder „u –v, v“ beschriftet ist und
es gilt π uv = u bzw. π uv = v
•
T hat Wurzel w, die mit „u – v, x“ beschriftet ist, und es gilt π uv = x . Zusätzlich
ist der linke Unterbaum von w ein (Π, u, x)-Wegbaum und der rechte Unterbaum
von w ein (Π, x, v)-Wegbaum
Siehe Abb. 6 – 8 als Beispiele für Matrix-Wegbäume.
Man sieht in den Beispielen, dass die Blätter der Matrix-Wegbäume gewissermaßen
redundant sind, weil ein Matix-Wegbaum ohne diese Blätter genauso aussagekräftig ist.
Wir werden sie aber trotzdem noch in jedes Beispiel einzeichnen, um Verwirrungen
vorzubeugen. In den allermeisten nachfolgenden Überlegungen kann man sie aber
ignorieren.
Wir sagen, ein Knoten x aus T (bzw. der dazu korrespondierende Matrix-Eintrag),
beschriftet mit „a – b, c“, korrespondiert zu einem Knoten y aus dem zugrundeliegenden
Straßennetz genau dann, wenn y = c.
1 Die Beschriftungen der Knoten sind etwas redundant, ein einfaches „x“ statt „u – v, x“ würde (zumindest im Kontext
eines gesamten Baumes) genauso aussagekräftig sein. Aber diese aufwendigere Beschriftung ist m.E. leichter
verständlich.
36
0-7,
6
0-6,
2
0-2,
1
0-1,
0
6-7,
6
2-6,
2
1-2,
1
Abb. 6: Matrix-Wegbaum für Matrix auf Tab. 2. Diese Abbildung stellt einen Matrix-Webbaum für
den Pfad von 0 nach 7 bzgl. der Matrix aus Tab. 2 dar.
0-7,
1
0-1,
1
1-7,
2
1-2,
2
2-7,
6
2-6,
6
6-7,
7
Abb. 7: Matrix-Wegbaum für Matrix aus Tab. 3. Zu sehen ist ein Matrix-Wegbaum für den Pfad von
0 nach 7 bzgl. der Matrix aus Tab. 3.
In den vorherigen drei Matrizen und Abbildungen haben wir gesehen, dass alle drei
Darstellungen desselben kürzesten Weges in der Floyd-Wege-Matrix möglich sind.
Vielleicht lässt sich dieser Freiheitsgrad ja für Straßennetze benutzen, um besonders
relevante Informationen eines oder mehrerer (kürzester) Wege durch das Auslesen
möglichst weniger Matrixeinträge zu erhalten. Dies wollen wir im nächsten Abschnitt
untersuchen.
37
0-7,
2
0-2,
1
0-1,
0
2-7,
6
1-2,
1
2-6,
2
6-7,
6
Abb. 8: Matrix-Wegbaum für Matrix aus Tab. 4. Hierbei handelt es sich um den Matrix-Wegbaum
für den Pfad von 0 nach 7 bzgl. der Matrix aus Tab. 4
4.2 Variante der Floyd-Wege-Matrix für Straßennetze
Im letzten Abschnitt haben wir gesehen, dass es Freiheitsgrade bei der Repräsentation
kürzester Wege in der Floyd-Wege-Matrix gibt. Diese möchten wir dazu benutzen, um für
bestimmte Anwendungen oder Anfragen bessere Laufzeiten dadurch zu erreichen, dass wir
die wichtigen Knotenpunkte der kürzesten Wege möglichst „weit oben“ in der FloydWege-Matrix speichern.
Was für Knotenpunkte auf (kürzesten) Wegen in einem Straßennetz sind normalerweise
besonders wichtig? Wenn man einem Menschen einen (kürzesten) Weg irgendwohin
beschreibt, dann sagt man ihm etwas wie z.B.: „Fahre die Museumstraße entlang, dann
biege in die Schloßallee ein, dann fährst du auf die Autobahn A3 auf, bei Abfahrt
Opernplatz runter von der Autobahn, auf die Parkstraße, ...“. Den Menschen interessiert
also meistens nur, wann die Straße gewechselt wird, und nicht jede einzelne Kante, weil er
ja anhand der Straßenschilder die Straßen(-namen) erkennen kann. Es gibt auch viele
Anfragen, für welche die Knoten auf einem kürzesten Weg, bei denen sich die Straße
ändert, wichtiger sind.
Es wäre nun schön, wenn sich Punkte x auf den Pfaden P von u nach v, wo von einer
Straße auf eine andere gewechselt wird, möglichst weit oben im entsprechenden MatrixWegbaum von einem dazu korrespondierenden Knoten (also einem Knoten mit
Markierung „u – v, x“) vertreten sind, weil man diese so schneller ausgeben kann bzw.
findet. Dies wollen wir nun formal auf den Punkt bringen:
Sei P = [v0, v1,..., vk-1, vk] ein Pfad in einem Straßennetz (V, E, S, T, w, s, t). Einen inneren
Knoten vi auf P, also vi ∈ P, i ≠ 0, i ≠ k, nennen wir Straßenwechselpunkt oder
Straßenwechselknoten bzgl. P gdw. s((vk-1, vk)) ≠ s((vk, vk+1)). Punkte auf Wegen, bei
denen sich der Straßentyp ändert (z.B. bei Autobahnauffahrten / -abfahrten), sind ebenfalls
wichtig: Einen inneren Knoten vi auf P, also vi ∈ P, i ≠ 0, i ≠ k, nennen wir
Straßentypwechselpunkt oder Straßentypwechselknoten bzgl. P gdw. t(s((vk-1, vk))) ≠
38
t(s((vk, vk+1))). Man sieht, dass ein Straßentypwechselknoten auch immer ein
Straßenwechselknoten ist, aber nicht unbedingt umgekehrt. Siehe dazu Abb. 9 als Beispiel:
Landstraße L1
0
Landstraße L2
1
Autobahn A1
2
3
Autobahn A2
4
5
Abb. 9: Ein Beispiel-Weg zur Veranschaulichung der Straßen(typ)wechselpunkte. Auf diesem Pfad
P = [0, 1, 2, 3, 4, 5] sind die Knoten 1, 2 und 4 Straßenwechselpunkte bzgl. P. Der Knoten 2 ist
darüber hinaus noch ein Straßentypwechselpunkt bzgl. P.
Wenn man es bei allen kürzesten Wegen P schafft, dass alle Straßenwechselknoten und
Straßentypwechselknoten des jeweiligen Weges (genauer gesagt, die dazu
korrespondierenden Knoten) „ganz oben“ in ihren jeweiligen Matrix-Wegbäumen sind,
dann kann man Anfragen1 wie z.B. „Finde alle Straßen auf dem kürzesten Weg von i nach
j“, „Geht der kürzeste Weg von i nach j über eine Autobahn?“ oder „Was ist die
Autobahnauffahrt / -abfahrt auf dem kürzesten Weg von i nach j?“ in jeweils Zeit
O(Anzahl Straßenwechselpunkte vom kürzesten Weg P von i nach j) herausfinden, was z.B.
gerade bei vielen redundanten Kanten (siehe Abschnitt 3.2.2) im Straßennetz deutlich
weniger sein kann als Θ(|P|). Das „ganz oben“ gilt es nun zu formalisieren:
Sei T ein Matrix-Wegbaum für einen Pfad P von u nach v bzgl. Matrix Π und v ein innerer
Knoten von T (also v sei kein Blatt). Wir nennen v einen Verstoß auf Klassenebene (bzgl.
T) oder Verstoß vom Typ A genau dann, wenn v nicht zu einem Straßentypwechselknoten
in P korrespondiert, aber sich im linken oder rechten Unterbaum von v ein innerer Knoten
befindet, der zu einem Straßentypwechselknoten korrespondiert. Wir nennen v einen
Verstoß auf Instanzebene (bzgl. T) oder Verstoß vom Typ B genau dann, wenn v nicht zu
einem Straßenwechselknoten in P korrespondiert, aber sich im linken oder rechten
Unterbaum von v ein innerer Knoten befindet, der zu einem Straßenwechselknoten
korrespondiert. Man sieht, dass Verstöße vom Typ A Spezialfälle von denen vom Typ B
sind.
Mit der Anzahl der Verstöße A bzw. B eines (Π, u, v)-Wegbaum T bezeichnen wir
(natürlich) die Anzahl der Knoten aus T, die Verstöße vom Typ A bzw. B sind. Wir sagen
ein (Π, u, v)-Wegbaum T hat (für uns) optimale Struktur genau dann, wenn die Anzahlen
der Verstöße auf Klassenebene als auch die Anzahl der Verstöße auf Instanzebene gleich 0
sind. Wenn dies für einen (Π, u, v)-Wegbaum T für einen Pfad P (von u nach v) zutrifft,
dann sind nämlich ganz oben im Baum die Knoten, die zu den Straßentypwechselknoten
1 Hierzu sind teilweise noch zusätzliche Verpointerungen / Referenzen und Informationen in den Datenstrukturen
notwenig. Diese fallen aber zumindest asymptotisch nicht ins Gewicht.
39
von P korrespondieren und etwas weiter unten, aber immer noch so weit oben wie
möglich, die Knoten, die zu den Straßenwechselknoten von P korrespondieren.
Hierzu beispielhaft zwei Matrix-Wegbäume für den Pfad aus Abb. 9:
0-5,
3
0-3,
1
0-1,
0
3-5,
4
1-3,
2
1-2,
1
3-4,
3
4-5,
4
2-3,
2
Abb. 10: Ein möglicher Matrix-Wegbaum den Pfad aus Abb. 9. Dieser Matrix-Wegbaum enthält 2
Verstöße vom Typ A („0-5, 3“, „0-3, 1“) und 2 Verstöße vom Typ B („0-5, 3“, „0-3“, 1“).
0-5,
2
0-2,
1
0-1,
0
2-5,
4
1-2,
1
4-5,
4
2-4,
3
2-3,
2
3-4,
3
Abb. 11: Ein weiterer möglicher Matrix-Wegbaum den Pfad aus Abb. 9. Dieser Matrix-Wegbaum
enthält keinerlei Verstöße und hat demnach optimale Struktur.
Bis jetzt haben wir definiert, wann ein einzelner Matrix-Wegbaum (für uns) optimale
Struktur hat. Zu definieren ist noch, wann eine ganze (Floyd-Wege-)Matrix, die ja viele
eineinander verschachtelte Matrix-Wegbäume enthält, (für uns) optimale Struktur hat:
Eine kürzeste Wegematrix Π hat (für uns) optimale Struktur genau dann, wenn für alle i, j
40
aus dem zugrundeliegenden Straßennetz N gilt: Der (Π, i, j)-Wegbaum hat optimale
Struktur.
Nachdem wir definiert haben, was wir unter einer optimalen Struktur einer Wege-Matrix
verstehen, ist noch nicht klar, ob es überhaupt eine Wege-Matrix gibt, die eine solche
Struktur hat. Zwar ist es leicht zu sehen, dass man einen einzelnen Pfad immer mit einem
(kürzesten) Matrix-Wegbaum darstellen kann, der optimale Struktur hat, aber eine
kürzeste-Wege-Matrix enthält ja sehr viele solcher Pfade, die jeweils Teilpfade
voneinander sind. Inhalt des nächsten Abschnittes ist ein Algorithmus, der es schafft, eine
gegebene Floyd-Wege-Matrix in eine gewissermaßen äquivalente zu transformieren, die
aber optimale Struktur hat (und damit ein konstruktiver Beweis für die Bejahung obiger
Frage ist).
4.3 Algorithmus zur Transformierung der Floyd-Wege-Matrix
Folgender Algorithmus erwartet als Eingabe eine Floyd-Wege-Matrix Π und ein
zugrundeliegendes
Straßennetz
bzw.
sonstige
Informationen
über
die
Straßentypwechselpunkte und Straßenwechselpunkte von den in der Floyd-Wege-Matrix
gespeicherten kürzesten Wege. Ausgegeben wird eine Matrix, welche immer noch alle
kürzesten Wege enthält, aber optimale Strukur hat:
Algorithmus: FLOYD-WEGE-MATRIX-OPTIMIERUNG
Eingabe: a) Straßennetz N = (V, E, S, T, w, s, t) mit V = {1, ..., n}
b) Floyd-Wege-Matrix Π für das obige Straßennetz
Ausgabe: Eine Matrix Π’ , welche (wie Π) kürzeste Wege von N enthält und optimale
Struktur hat
Methode:
for i := 1 to n
do
for j := 1 to n, j ≠ i
do
Ermittle den kürzesten Pfad P von i nach j in Π;
if |P| ≤ 1
then
π 'ij := π ij ;
else
if (es gibt einen Straßentypwechselknoten k auf P)
then
π 'ij := k ;
else
if (es gibt einen Straßenwechselknoten k auf P)
then
41
π 'ij := k ;
else
π 'ij := irgendein Knoten k echt innerhalb von P;
fi
fi
fi
od
od
return Π’;
‫ڤ‬
Bevor wir uns Gedanken um die Korrektheit des Algorithmus machen, betrachten wir ein
Beispiel (Abb. 12 und Tab. 5).
Es ist nicht besonders schwer zu sehen, dass der Algorithmus, angewendet auf nur einen
Pfad und alle seine Teilpfade, funktioniert, da er ziemlich direkt die Definition der
Verstöße und der optimalen Struktur benutzt. Dass dies aber auch bei einer ganzen FloydWege-Matrix funktioniert, ist nicht so klar. Dazu eine neue Definition:
Einen Eintrag πij = k in der Floyd-Wege-Matrix nennen wir Wurzelverstoß auf
Klassenebene oder Wurzelverstoß vom Typ A genau dann, wenn im (Π, i, j)-Wegbaum die
Wurzel ein Verstoß vom Typ A ist. Analog definieren wir einen Wurzelverstoß auf
Instanzebene oder Wurzelverstoß vom Typ B. Es zeigt sich nun, dass diese Wurzelverstöße
mit der Optimalität der Floyd-Wege-Matrix stark korreliert sind:
Lemma 10:
Sei (V, E, S, T, w, s, t) ein Straßennetz und Π eine Floyd-Wege-Matrix kürzester Wege
dafür. Falls Π keine Wurzelverstöße vom Typ A und keine Wurzelverstöße vom Typ B
enthält, dann hat Π optimale Struktur.
Beweis:
Zu zeigen ist, dass für alle i, j gilt: Der (Π, i, j)-Wegbaum hat keine Verstöße vom Typ A
und keine Verstöße vom Typ B. Dazu schauen wir uns für beliebiges i und j (i ≠ j) den (Π,
i, j)-Wegbaum an:
Die Wurzel des Baumes ist mit „i – j, k“, der linke Sohn der Wurzel mit „i – k, x“ und der
rechte Sohn mit „k – j, y“ beschriftet.
Nach Vorraussetzung ist die Wurzel kein Verstoß vom Typ A oder B. Der linke Sohn ist
Wurzel des (Π, i, k)-Wegbaumes und ist deswegen auch kein Verstoß vom Typ A oder B.
Gleiches gilt für den rechten Sohn und die Söhne der Söhne und damit allen Knoten des
(Π, i, j)-Wegbaumes.
42
‫ڤ‬
1
4
5
Landstraße L3
2
1
Autobahn A2
3
2
9
1
3
2
1
Autobahn A1
2
1
1
Landstraße L2
6
3
3
8
8
Landstraße L1
7
0
Abb. 12: Beispiel-Straßennetz. Dieses Straßennetz ist eine Erweiterung des Graphen aus Abb. 2. Die
Beschriftungen innerhalb der Knoten sind die Knotenbezeichnungen und die Beschriftungen an
den Kanten e stellen die Kantengewichte w(e) dar. Die Farben, zusammen mit der
entsprechenden Beschriftung, kennzeichnen die Straßen und Straßentypen.
πij
0
1
2
3
4
5
6
7
8
9
0
1
1
1
1
1
1
1
1
1
1
0
2
2
2
2
2
2
2
2
2
1
1
3
3
3
6
6
9
9
3
2
2
2
4
4
2
2
2
2
4
3
3
3
3
5
3
3
5
5
5
9
9
9
4
4
9
9
9
9
6
2
2
2
2
2
2
7
7
2
7
6
6
6
6
6
6
6
8
6
8
9
9
9
9
9
9
7
7
9
πij’
0
1
2
3
4
5
6
7
8
9
9
2
2
2
2
2
2
2
2
8
-
0
1
1
2
2
4
2
2
9
1
1
0
2
2
2
4
2
2
9
2
2
1
1
3
3
4
6
6
9
9
3
2
2
2
4
4
2
2
9
2
4
2
2
3
3
5
2
2
9
5
5
9
9
9
4
4
2
2
9
9
6
2
2
2
2
2
4
7
7
2
7
2
2
6
2
2
4
6
8
2
8
9
9
9
9
9
4
7
7
9
9
2
2
2
2
2
4
2
2
8
-
Tab. 5: Anwendung des Algorithmus FLOYD-WEGE-MATRIX-OPTIMIERUNG auf die Floyd-WegeMatrix zu Abb. 12. Die linke Matrix ist die Floyd-Wege-Matrix Π für das Straßennetz aus
Abb. 12. Die rechte ist die vom Algorithmus FLOYD-WEGE-MATRIX-OPTIMIERUNG
zurückgegebene Matrix Π’, welche im Gegensatz zu Π optimale Struktur hat (und immer noch
die kürzesten Wege von Abb. 12 speichert).
Nun schauen wir uns die Eigenschaften der zurückgegebenen Matrix Π’ an:
Lemma 11:
Sei (V, E, S, T, w, s, t) ein Straßennetz und Π eine Floyd-Wege-Matrix kürzester Wege
dafür. Bei Eingabe Π und (V, E, S, T, w, s, t) gilt nach Terminierung für die vom
43
Algorithmus
Folgendes:
FLOYD-WEGE-MATRIX-OPTIMIERUNG
zurückgegebene
Matrix
Π’
a) Π’ enthält wie Π alle kürzesten Wege für (V, E, S, T, w, s, t)
b) Π’ enthält keine Wurzelverstöße vom Typ A und keine Wurzelverstöße vom Typ B
Beweis:
Zu a)
Diese Behauptung zeigen wir durch Induktion über die Anzahl m der Zuweisungen π’ij :=
k für eine Matrix Π* , welche folgendermaßen definiert ist: π*ij = π’ij falls π’ij schon
definiert und π*ij = πij sonst. Da nach der letzten solchen Zuweisung sicherlich Π* = Π’
gilt, zeigt dies die Behauptung.
Induktionsanfang:
Bei m = 0 ist Π* = Π und damit die Behauptung erfüllt
Induktionsannahme:
Die Behauptung gilt für m = l – 1
Induktionsschritt:
Vor der m = l. Zuweisung π’ij := k (bzw. π*ij := k) galt π’ij := k’ (bzw. π*ij := k’) und der in
Π* gespeicherte kürzeste Pfad P’ von i nach j (Induktionsannahme) hatte die Struktur P’ =
P1’, P2’, P3’, wobei wegen k, k’ ∈ P’ entweder
i) P1’ = [i, ..., k’] ein (kürzester) Pfad von i nach k’ ist,
P2’ = [k’, ..., k] ein (kürzester) Pfad von k’ nach k ist und
P3’ = [k, ..., j] ein (kürzester) Pfad von k nach j ist oder
ii) P1’ = [i, ..., k] ein (kürzester) Pfad von i nach k ist,
P2’ = [k, ..., k’] ein (kürzester) Pfad von k nach k’ ist und
P3’ = [k’, ..., j] ein (kürzester) Pfad von k’ nach j ist.
Wir betrachten nur Fall i), weil Fall ii) symmetrisch dazu ist:
Nach der m = l. Zuweisung π’ij := k (bzw. π*ij := k) hat der in Π* gespeicherte kürzeste Pfad
P von i nach j die Struktur P = P1, P2, wobei wegen der Induktionsvorraussetzung P1 = [i,
..., k] ein kürzester Pfad von i nach k ist und P2 = [k, ..., j] ein kürzester Pfad von k nach j
ist. Daraus folgt, dass w(P1) ≤ w(P1’) + w(P2’) und w(P2) ≤ w(P3’) und dadurch w(P) ≤
w(P’).
Zu b)
Offensichtlich ist diese Behauptung erfüllt (siehe Definition und Algorithmus).
‫ڤ‬
44
Aus den beiden vorherigen Lemmata folgt nun ziemlich direkt die Korrektheit vom
Algorithmus FLOYD-WEGE-MATRIX-OPTIMIERUNG:
Satz 3:
Der Algorithmus FLOYD-WEGE-MATRIX-OPTIMIERUNG ist korrekt und in Zeit Θ(n2α)
implementierbar, wobei α die durchschnittliche ungewichtete Länge eines kürzesten
Pfades in dem Eingabe-Straßennetz ist.
Beweis:
Zur Korrektheit ist zu zeigen, dass nach einer Eingabe, welche die Eingabe-Spezifikation
erfüllt, der Algorithmus mit der im Ausgabe-Teil des Algorithmus beschriebenen Ausgabe
terminiert. Dies folgt direkt aus den Lemmata 10 und 11.
Die Laufzeit ist Θ(n2α), weil wir für die Bestimmung des kürzesten Pfades P bzw. der
Straßenwechselknoten und Straßentypwechselknoten von P jeweils Zeit Θ(|P|) brauchen –
also im Durchschnitt (arithmetisches Mittel) Θ(α) bei insgesamt n2 (genau genommen bei
entsprechender Implementation n2 – n) kürzesten Pfaden.
‫ڤ‬
Da die durchschnittliche ungewichtete Länge eines Pfades sicher kleiner n ist, ist die
Laufzeit natürlich auch O(n3). Wie lang diese Länge im Einzelfall tatsächlich ist, hängt
vom betrachteten Graphen / Straßennetz ab.
In diesem Abschnitt haben wir also gesehen, wie wir eine Floyd-Wege-Matrix in O(n3) so
transformieren können, dass sie die im vorherigen Abschnitt definierte optimale Struktur
hat. Im nächsten Abschnitt wollen wir uns eine Beispiel-Anwendung anschauen, die schon
etwas mit dem Kapitel 5 zu tun und auch zu den Überlegungen in jenem Kapitel geführt
hat.
4.4 Beispielanwendung
Die Variante der Floyd-Wege-Matrix, die wir in den vorherigen Abschnitten kennen
gelernt haben, speichert alle kürzesten Wege derart, dass wir bei bestimmten kürzesteWeg-Anfragen an sie nicht immer den ganzen Weg (jeden Knoten bzw. Kante) betrachten
bzw. ausgeben müssen. Wenn man z.B. nur eine Sequenz der verschiedenen Straßen eines
kürzesten Weges P in ihrer Vorkommensreihenfolge erfahren möchte (so ähnlich
beschreibt man einem Menschen einen Weg normalerweise), dann lässt diese Anfrage in
Zeit Θ(Anzahl Straßenwechselpunkte) anstatt in Θ(|P|) beantworten. Jetzt wollen wir uns
eine komplexere Anwendung anschauen, welche schon etwas mit dem nächsten Kapitel zu
tun hat und auch Auslöser für die dortigen Überlegungen und dementsprechend dem
zweiten Schwerpunkt dieser Diplomarbeit war. Die Idee zu dieser Anwendung kommt
auch von Prof. Plümer.
45
Zur Beschreibung dieser Anwendung brauchen wir zuerst eine Definition, um
Missverständisse zu vermeiden. Sei N = (V, E, S, T, w, s, t) ein Straßennetz. Wir nennen
ein Straßennetz N’ = (V’, E’, S’, T’, w’, s’, t’) Straßenunternetz1 von N genau dann, wenn
•
V’ ⊆ V
•
E’ ⊆ E und für alle (u, v)∈E’ gilt: u∈V’ und v∈V’
•
S’ ⊆ S
•
T’ ⊆ T
•
w’(e) = w(e) für alle e ∈ E’
•
s’(e) = s(e) für alle e ∈ E’
•
t’(e) = t(e) für alle e ∈ E’
Ein Straßenunternetz ist also nichts Anderes als einfach ein Teil eines Straßennetzes.
Im Folgenden stellen wir noch zweierlei Anforderungen an das Straßennetz. Zum einen
gebe es immer maximal einen kürzesten Weg zwischen zwei (verschiedenen) Punkten des
Straßennetzes (siehe dazu eine spätere Fußnote). Zum anderen (und an sich auch o.B.d.A.)
gebe es in unserem Straßennetz nur zwei Typen von Straßen: Landstraßen und
Autobahnen. Also T = {Landstraße, Autobahn}.
Betrachten wir jetzt ein bestimmtes Unternetz von N, das sogenannte Autobahnnetz A,
welches aus den Autobahnkanten und dazu gehörenden Knoten besteht. Also A = (VA, EA,
SA, {Autobahn}, wA, sA, tA) mit EA der Menge aller Kanten e, welche zu Straßen vom Typ
Autobahn gehören, also t(s(e)) = Autobahn, und der Menge VA aller Knoten v, welche zu
Kanten aus EA inzident sind. Die Funktionen wA, sA, tA sind wie w, s bzw. t, nur
entsprechend auf die Untermenge VA von V beschränkt.
Angenommen, man würde das Autobahnnetz separat vom Gesamt-Straßennetz N
speichern und es dazu benutzen wollen, kürzeste Wege (bzgl. N) zwischen Knoten des
Autobahnnetzes zu finden, dann gibt es Fälle, bei denen denen dies nicht klappt, weil der
kürzeste Weg zwischen den Autobahnknoten nicht über das Autobahnnetz geht, sondern
über Landstraßen. Hierzu ein Beispiel aus der realen Welt (Abb. 13):
1 Zur Definition des Straßenunternetzes ist zu bemerken, dass sie nicht mit der späteren Definition von Straßensubnetz
zu verwechseln ist.
46
Abb. 13 Straßenkarten-Ausschnitt in der Nähe von Mayen. Hier ist ein Ausschnitt einer
handelsüblichen Straßenkarte. Was hieran interessant ist, ist dass der kürzeste Weg von der
A48, Abfahrt Mayen, zur A61, Abfahrt Mendig, nicht über die beiden Autobahnen geht (das
ist sowohl von der geometrischen Länge als auch von der Zeit her ein großer Umweg),
sondern ab der Abfahrt Mayen über die B262 und dann weiter nördlich über weitere
Bundesstraßen verläuft.
Wir wollen nun folgendes Problem mit Hilfe der Variante der Floyd-Wege-Matrix
(effizienter als ohne) lösen: Die Erweiterung des Autobahnnetzes A in A’ um eine (von der
Kardinalität her) minimale Anzahl von Kanten des Typs Landstraße aus N, so dass jeder
kürzeste Pfad in N zwischen zwei Knoten des ursprünglichen Autobahnnetzes A auch in
dem erweiterten Autobahnnetz A’ liegt. Dann kann man nämlich A’ (welches
wahrscheinlich deutlich kleiner als N sein wird) zur Berechnung kürzester Pfade zwischen
Autobahnknoten benutzen. Folgender Algorithmus löst genau dieses Problem mit der
Variante der Floyd-Wege-Matrix:
Algorithmus: AUTOBAHNNETZ_ERWEITERUNG
Eingabe: a) Straßennetz N = (V, E, S, T, w, s, t) mit V = {1, ..., n} mit
i) Es gibt maximal einen kürzesten Weg zwischen zwei verschiedenen
Knoten
ii) T = {Landstraße, Autobahn}
b) Variante der Floyd-Wege-Matrix Π für das obige Straßennetz
47
Ausgabe: Eine von der Kardinalität her minimale Liste L von Landstraßen-Kanten, so
dass, wenn man das Autobahnnetz um diese (und um die (End-)Knoten der
Kanten) erweitert, jeder kürzeste Weg zwischen zwei Knoten des
ursprünglichen Autobahnnetzes innerhalb des erweiterten liegt.1
Methode:
L := Ø;
for all (i, j)∈{(u, v)∈V× V | u ist inzident zu einer Autobahn-Kante,
v ist inzident zu einer Autobahn-Kante und
u ≠ v}
do
if ( π ij = i) // besteht der kürzeste Pfad von i nach j aus nur einer Kante?
then
e := diese Kante (i, j);
if (e ist Landstraßen-Kante)
then
L := L ∪ {e};
fi
else
if ( π ij ist nicht inzident zu einer Autobahn-Kante) // ⇒ nur Landstraßen-
// kanten auf dem Weg
von
// i nach j in Π (*)
then
L := L ∪ {alle Kanten e auf dem Pfad in Π von i nach j}
fi
fi
od
return L;
‫ڤ‬
Nun wollen wir die Korrektheit und Laufzeit dieses Algorithmusses zeigen:
Satz 4:
Der Algorithmus AUTOBAHNNETZ-ERWEITERUNG ist korrekt und in Zeit O(n2)
implementierbar.
1 Falls im betrachteten Straßennetz nicht die Eigenschaft a) i) erfüllt ist, dann hat die Liste L nicht notwendigerweise
minimale Kardinalität, weil die (Variante der) Foyd-Matrix die „falschen“ bzw. für diesen Algorithmus
ungünstigen kürzesten Wege gespeichert haben kann. Dies sind kürzeste Wege, die über Landstraßen-Kanten
gehen, obwohl es gleich schnelle nur über Autobahn-Kanten oder über weniger Landstraßen-Kanten gibt
48
Beweis:
Zur Korrektheit zeige ich folgendes:
(i) an Stelle (*) im Algorithmus gilt: π ij ist nicht inzident zu einer Autobahn-Kante (A)
⇒
es gibt nur Kanten vom Typ Landstraße auf dem kürzesten Weg von i nach j in Π (B).
(ii)
die Kanten eines jeden kürzesten Pfades P zwischen zwei Knoten i, j, die jeweils
inzident zu einer Autobahnkante sind, sind in nach Beendigung des Algorithmus in L
enthalten.
Zu (i)
Ich zeige nun, dass aus der Gültigkeit von (A) (B) folgt. Da Π optimale Struktur hat, ist,
wenn möglich, ein π ij Straßentypwechselpunkt. In dem Fall wäre aber π ij inzident zu
einer Autobahn-Kante. Also kann π ij kein Straßentypwechselpunkt sein. Daraus folgt,
dass auf dem ganzen Pfad von i nach j nur der gleiche Straßentyp vorliegt. Da π ij eben zu
keiner Autobahnkante inzident ist, kann es sich dabei nur um Landstraßen handeln.
Zu (ii)
Sei P ein kürzester Pfad zwischen zwei Knoten i, j, die jeweils inzident zu einer
Autobahn-Kante sind. Dieser Pfad lässt sich in Teilpfade aufteilen, so dass diese jeweils
mit einem zu einer Autobahn-Kante inzidenten Knoten beginnen und mit einem solchen
Knoten enden und kein innerer Knoten dieser Pfade zu einer Autobahnkante inzident ist.
Alle diese Teilpfade werden irgendwann im Verlauf des Algorithmus betrachtet und zu L
hinzugefügt.
Die Laufzeit ergibt sich aus folgenden Tatsachen:
a) man kann in O(n2) Zeit herausfinden kann, welche Knoten zu Autobahn-Kanten
inzident
sind
b) die Schleife wird O(n2) mal durchlaufen
c) Die einzigen Teile innerhalb der Schleife, die nicht O(1) Zeit benötigen, lassen sich den
einzelnen Kanten zuordnen. Jede dieser O(n2) Kanten wird maximal einmal zugeordnet.
‫ڤ‬
49
50
5
Anwendung der Variante der Floyd-Wege-Matrix in einem
hierarchischen Strassennetz
Im Kapitel 4 haben wir eine Variante der Floyd-Wege-Matrix kennengelernt, welche es
uns ermöglicht, bestimmte Anfragen an ein Straßennetz bzgl. kürzester Wege effizienter
zu beantworten als dies mit der einfachen Floyd-Wege-Matrix möglich ist. Bei der Suche
nach Anwendungen kam die Idee, diese zu verwenden, um aus einem gewissermaßen
„flachen“ Straßennetz (so wie wir es bisher immer betrachtet haben) ein hierarchisches
Straßennetz zu generieren, mit dessen Hilfe sich kürzeste-Weg-Anfragen in kurzer Zeit
(normalerweise schneller als Dijkstra) und bei vertretbaren Speicherplatzaufwand
(normalerweise weniger als Floyd) beantworten lassen.
Für dieses Verfahren leiten wir zwei Algorithmen her: Der eine generiert uns aus einem
gegebenen, „normalen“ Straßennetz ein hierarchisches unter Verwendung einer Heuristik,
welche Verwaltungstrukturen aus der realen Welt wie Landkreise und die gegebene
Hierarchie des Straßennetzes (Landstraßen, Bundestraßen, Autobahnen, etc.) ausnutzt
(Abschnitt 5.2). Der andere benutzt ein solches hierarchisches Straßennetz dann zur
Bestimmung exakter kürzester Wege (Abschnitt 5.1). Im Abschnitt 5.2.1 untersuchen wir
Optimierungskriterien, welche solche hierarchischen Straßennetze möglichst erfüllen
sollten. In Abschnitt 5.2.3 betrachten wir konkrete Worst-Case Fälle für die Heuristik und
einen Best-Case-Fall, der hoffentlich bei Anwendung der Heuristik auf reale Straßennetze
– im Gegensatz zu konstruierten worst-case-Beispielen – eher die Regel ist.
In diesem Kapitel betrachten wir die Verwendung der Floyd-Wege-Matrix in zweierlei
Hinsicht. Zum einen untersuchen wir die Verwendung des Algorithmus
AUTOBAHNNETZ_ERWEITERUNG in der Heuristik zur Generierung des hierarchischen
Straßennetzes (Abschnitt 5.2), welche sich als nicht unbedingt vorteilhaft, aber auch nicht
unbedingt nachteilhaft erweist. Zum anderen benutzen wir sie später als Datenstruktur in
dem hierarchischen Straßennetz, wo sie definitiv Sinn macht.
In diesem Kapitel wurde keine spezielle Literatur benutzt.
5.1 Grundmodell
In diesem Abschnitt betrachten wir ein Verfahren, wie man kürzeste Wege in einer
bestimmten Art von hierarchischem Straßennetz (welches wir auch in diesem Kapitel
definieren werden) berechnen kann. Dieses Verfahren garantiert optimale Lösungen
kürzester-Weg-Anfragen (ist also in dieser Hinsicht keine Heuristik). Je nachdem, welche
51
Datenstrukturen man benutzt, ergeben sich unterschiedliche Laufzeiten und
Speicherplatzanforderungen. Wie man so ein hierarchisches Straßennetz aus einem
Straßennetz aus der realen Welt erhält, ist Thema von Abschnitt 5.2.
5.1.1 Idee
Dem in diesem Kapitel betrachteten Verfahren zur Berechnung kürzester Wege liegt
folgende Idee zugrunde: Angenommen, man möchte z.B. mit dem Auto vom
Hauptgebäude der Universität von Bonn nach Hamburg zum Hauptgebäude der dortigen
Univerität fahren. Dann sieht der kürzeste Weg dahin so aus: Man fährt zuerst über einige
Straßen niederer Ordnung, dann auf eine Autobahn, danach – den größten Teil der Strecke
– über diverse Autobahnen und zuletzt von der Autobahn wieder herunter auf Straßen
niederer Ordnung bis zur Universität in Hamburg.
Angenommen, jeder kürzester Weg hätte diese Struktur, dann könnte man das GesamtStraßennetz Deutschlands in verschiedene Regionen1 und ein Autobahn(unter)netz
aufteilen und kürzeste Wege nur mit Hilfe der Region des Startknotens des Weges, der
Region des Zielknotens und dem Autobahnnetz folgendermaßen berechnen: Man
betrachtet alle Paare von Autobahnauffahrten in der Region des Startknotens auf der einen
Seite und Autobahnabfahrten in der Region des Zielknotens auf der anderen Seite und
ermittelt das Paar, welches die Gesamtlänge des konkatenierten Weges von Startknoten
zur Autobahnauffahrt zur Autobahnabfahrt zum Zielknoten minimiert. Dieser Weg muss
dann der kürzeste sein und kann nur durch die drei Teile des Gesamtstraßennetzes
ermittelt werden.
Ist es zu erwarten, dass die Annahme, dass alle kürzesten Wege in realen Straßennetzen
immer die Struktur „Straßen niederer Ordnung – Autobahnauffahrt innerhalb der Region
des Startknotens – Autobahnen – Autobahnabfahrt innerhalb der Region des Zielknotens –
Straßen niederer Ordnung bis zum Zielknoten“ haben? Nein, bei den meisten
Straßennetzen (und Autobahnunternetzen) und Einteilungen derer in Regionen wohl nicht,
denn
•
Knoten, die innerhalb derselben Region liegen, sind oftmals nicht sehr weit
voneinander entfernt, so dass der kürzeste Weg vermutlich nicht über Autobahnen
geht.
•
Bei Knoten, die in benachbarten Regionen liegen, ist auch zu erwarten, dass der
kürzeste Weg oft nicht über Autobahnen geht.
1 Der Begriff Region ist in einem sehr intuitiven Sinn gemeint. Formaler kann man sich unter dieser Regionalisierung
z.B. eine Tesselation der Ebene oder (mehr auf Straßennetze bezogen) eine disjunkte, vollständige Einteilung
aller Knoten (und dadurch auch der Kanten) in bzgl. den Kanten zusammenhängende, möglichst konvexe
Teilmengen vorstellen. Später wird dies (natürlich) genau auf den Punkt gebracht.
52
•
Abb. 13 zeigt, dass in realen Straßennetzen das Autobahnnetz nicht immer perfekt
ist und bzgl. kürzester Wege in Straßennetzen nicht abgeschlossen ist.
•
Ferner kann es natürlich sein, dass, je nachdem wie man das gesamte Straßennetz
in Regionen eingeteilt hat, die Autobahnauffahrt oder die Autobahnabfahrt eines
kürzesten Weges nicht in der Region des Startknotens bzw. des Zielknotens liegt.
Aber es ist zu erwarten (zumindest zu erhoffen), dass die meisten kürzesten Wege
zwischen zwei „weit“ voneinander entfernten Punkten die Struktur „Straßen niederer
Ordnung – Autobahnen – Straßen niederer Ordnung“ haben, denn das Autobahnnetz ist ja
dazu da, Kraftfahrzeugen zu ermöglichen, schneller von einem Punkt zu einem anderen zu
kommen als über normale Straßen und dementsprechend sorgfältig geplant und angelegt.
Dieses auf intuitiver Ebene für reale Straßennetze skizzierte Verfahren zur Bestimmung
kürzester Wege wollen wir nun im nächsten Abschnitt genauer betrachten.
5.1.2 Straßensubnetze
Im vorherigen Abschnitt haben wir von „Regionen“ gesprochen und dies in einem sehr
intuitiven Sinne gemeint. Eine Einteilung eines Straßennetzes in solche Regionen, so dass
der vorhin skizzierte Algorithmus zur Bestimmung kürzester Wege (der in Abschnitt 5.1.3
komplett und formal beschrieben wird) immer funktioniert, wollen wir nun formal
definieren.
Die folgende Definition definiert das hierarchische Straßennetz, von dem wir bisher
gesprochen haben. Diese Definition und der Algorithmus im nächsten Abschnitt, obwohl
definiert für Straßennetze N, basieren an sich auf gewichteten, gerichteten Graphen G =
(V, E, w), weil nichts von S, T, s, t im Algorithmus verwendet wird. Ich habe mich aber
dafür entschieden, nicht so allgemein wie möglich zu bleiben (und hier von gerichteten,
gewichteten Graphen anstatt von Straßennetzen zu sprechen), da sonst das Verständnis
darunter leiden könnte (zumal es auch leicht zu sehen ist, wie man die Definition
„verallgemeinern“ kann).
Wir nennen ein Tupel X = ({H}, {L1, L2, ..., Lp}, f) eine Einteilung eines Straßennetzes N =
(V, E, S, T, w, s, t) in (Straßen-)Subnetze genau dann, wenn
1) H = (V[H], E[H], S[H], T[H], w[H], s[H], t[H]) ein Straßenunternetz1 von N ist,
2) für alle 1 ≤ i ≤ p gilt : Li = (V[Li], E[Li], S[Li], T[Li], w[Li], s[Li], t[Li]) ist ein
Straßenunternetz von N,
1 Zur Definition eines Straßenunternetzes siehe Abschnitt 4.3
53
3) f: V → { L1, L2, ..., Lp} ist eine Funktion, welche die einzelnen Knoten ihrem
jeweiligem Stammsubnetz zuordnet und es gilt: v∈V[f(v)].
4) für alle u, v ∈ V mit f(u) ≠ f(v) gilt für mindestens einen kürzesten Pfad P = [e1, e2, ...,
ek-1, ek] von u nach v, falls solcher existiert, mindenstens einer der folgenden Punkte:
a) Der Pfad P ist vollständig (mit allen Knoten und Kanten) in f(u) enthalten.
b) Es gibt zwei Teilpfade P1 = [e1, ..., ex] und P2 = [ex+1, ..., ek] von P, wobei ex = (c,
d), so dass P1 vollständig in f(u), P2 vollständig in f(v) enthalten sind und
d∈V[H] gilt. Diese Teilpfade können auch leer bzw. triviale Pfade [(e, e)] sein (die
Konkatenation muss aber den Pfad P ergeben) 1.
c) Es gibt drei Teilpfade P1 = [e1, ..., ex], P2 = [ex+1, ..., ey] und P3 = [ey+1, ..., ek] von P,
so dass P1 vollständig in f(u), P2 vollständig in H und P3 vollständig in f(v)
enthalten sind. Diese Teilpfade können auch leer bzw. triviale Pfade [(e, e)] sein
(die Konkatenation muss aber den Pfad P ergeben).
5) für alle u, v ∈ V mit mit f(u) = f(v) gilt: Der kürzeste Pfad von u nach v, falls ein
solcher existiert, ist vollständig in f(u) enthalten.
Hierbei bezeichnen wir H als das High-Level (Straßen-)Subnetz und L1, ..., Lp als LowLevel (Straßen-)Subnetze und meinen mit (Straßen-)Subnetz entweder ein High- oder
Low-Level-Subnetz.
Zu dieser Definition ist Folgendes zu bemerken:
•
Es ist ganz bewusst nicht verlangt, dass das High-Level-Subnetz einer solchen
Subnetz-Einteilung X eines Straßennetzes N aus Autobahnen bestehen muss.
Zumindest für das Erste kann man sich aber zum leichteren Verständnis unter
dem High-Level-Subnetz das Autobahnunternetz des betrachteten Straßennetzes
vorstellen
(oder
z.B.
auch
das
durch
den
Algorithmus
AUTOBAHNNETZ_ERWEITERUNG erweiterte Autobahnunternetz).
•
Im Prinzip sind die Mengen V[Li] ∩ V[H] die Zugänge vom Low-Level-Subnetz
Li zum High-Level-Subnetz H bzw. die Autobahnauffahrten und –abfahrten. Dies
sollte spätestens beim nächsten Algorithmus klar werden.
•
Für die englischen Begriffe High-Level- und Low-Level-Subnetz habe ich mich
entschieden, weil sie prägnanter sind als die deutschen Alternativen, die mir
eingefallen sind, und relativ allgemein sind.
•
In der Definition soll (natürlich) V[▪], E[▪], etc. nicht eine implementierte
Funktion oder Array oder sonstiges Derartiges darstellen, sondern dient nur der
Bezeichnung.
1 Dies ist nicht 100% formal definiert, aber für die Intuition förderlich, denke (und hoffe) ich.
54
•
Die Definition X = ({H}, {L1, L2, ..., Lp}, f) habe ich so definiert, weil es meiner
Meinung sich leicht in höhere Hierarchie-Dimensionen1 auf zentrale Art und
Weise2 verallgemeinern lässt: So könnte man z.B. für Dimension d die Einteilung
wie nachstehend definieren:
X := {H d }, {H 1d −1 ,..., H edd−−11 },..., {H 11 ,..., H e11 }, {L1 ,..., L p }, f )
•
Dies ist eine rein theoretische Definition, in der nichts darüber ausgesagt wird,
wie die Subnetze in einem Rechner gespeichert werden. Solange es möglich ist,
werden wir uns darüber auch keine Gedanken machen, da die später hergeleiteten
Algorithmen in dieser Hinsicht auch relativ flexibel sind. Erst in Abschnitt 5.3.1
werden wir uns konkrete Datenstrukturen anschauen (und z.T. auch schon ein
wenig in den Laufzeitanalysen der folgenden Algorithmen). Es dürfte hierbei
auch klar sein, dass man die Zugänge zwischen den Subnetzen in praktischen
Implementationen wohl irgendwie explizit machen würde und nicht so elegant
theoretisch implizit wie hier.
5.1.3 Algorithmus zur Ermittlung kürzester Wege
Im letzten Abschnitt haben wir definiert, was eine Einteilung eines Straßennetzes in
Subnetze ist. Nun schauen wir uns den schon in 5.1.1 skizzierten Algorithmus für die
Bestimmung kürzester Wege innerhalb eines hierarchischen Straßennetzes an, aber
diesmal komplett und formal auf der Grundlage der Definition des vorherigen Abschnitts:
Algorithmus: HIERARCHISCHE_WEGBERECHNUNG
Eingabe: a) Bzgl. einer Einteilung X = ({H}, {L1, L2, ..., Lp}, f) des Straßennetzes
N = (V, E, S, T, w, s, t) mit V = {1, ..., n}in Subnetze Folgendes:
i) Startknoten i∈V und Zielknoten j∈V des zu berechnenden Pfades
ii) das High-Level-Subnetz H = (V[H], E[H], S[H], T[H], w[H], s[H],
t[H]) von X
iii) das Low-Level Subnetz L(1) = (V[L(1)] , E[L(1)], S[L(1)], T[L(1)], w[L(1)],
s[L(1)], t[L(1)]) von X, s.d. f(i) = L(1) (Stammsubnetz von i)
iv) das Low-Level Subnetz L(2) = (V[L(2)], E[L(2)], S[L(2)], T[L(2)], w[L(2)],
s[L(2)], t[L(2)]) von X, s.d. f(j) = L(2) (Stammsubnetz von j)
v) der zu i korrespondierende Knoten in L(1), der zu j korrespondierende
Knoten in L(2) und der zu j korrespondierende Knoten in L(1), falls
dieser
1 Ich bin mir nicht sicher, ob man bei solchen Hierarchien von Dimensionen spricht, aber es dürfte auf intuitive Weise
gut verständlich sein.
2 Ein rekursiver Ansatz wäre vielleicht noch schöner, weil ja ein Straßensubnetz auch selber wieder ein Straßennetz ist,
dass ja wieder in Straßensubnetze eingeteilt sein könnte...
55
existiert, seien bekannt (bzw. diese werden anstatt i und j aus N übergeben).
Ausgabe: entweder den kürzesten Pfad in N zwischen dem Startknoten i und dem
Zielknoten j und dessen Länge oder, falls kein solcher existiert, „[], ∞“
Methode:
if L(1) = L(2)
then
berechne δ(i, j) und ggf. den kürzesten Weg P von i nach j innerhalb L(1) ;
return P, δ(i, j) bzw. Ø, ∞;
fi
dmin := ∞;
for all a∈ (V[L(1)] ∩ V[H]) // (V[L(1)] ∩ V[H]) ist die Menge der Auffahrten /
// Ausgänge von L(1) zu H (zumindest im Prinzip)
do
for all e∈ (V[L(2)] ∩ V[H]) // (V[L(2)] ∩ V[H]) ist die Menge der Abfahrten /
// Eingänge von in L(2) von H kommend
do
berechne durch das Subnetz L(1): d(1) := δ L(1) (i, a); // = δ N (i, a)
berechne durch das Subnetz H: dH := δ H (a, e); // = δ N (a, e)
berechne durch das Subnetz L(1): d(2) := δ L( 2 ) (e, j); // = δ N (e, j)
if d(1) + dH + d(2) < dmin
then
dmin := d(1) + dH + d(2);
amin := a;
emin := e;
fi
od
od
if j∈L(1)
then
if δ L(1) (i, j) ≤ dmin
then
ermittle durch das Subnetz L(1) den kürzesten Pfad P von i nach j;
return P, δ L(1) (i, j);
fi
fi
if dmin < ∞
56
then
ermittle durch das Subnetz L(1) den kürzesten Pfad P(1) von i nach a;
ermittle durch das Subnetz H den kürzesten Pfad PH von a nach e;
ermittle durch das Subnetz L(2) den kürzesten Pfad P(2) von a nach j;
konkateniere P(1), PH und P(2) zu Pmin // wobei (natürlich) das jeweils zweite Vor// kommen von a und e gestrichen wird
return Pmin, dmin;
else
return [], ∞;
fi
‫ڤ‬
Nun wollen wir die Korrektheit und Laufzeit dieses Algorithmusses zeigen:
Satz 5:
Der Algorithmus HIERARCHISCHE_WEGBERECHNUNG ist korrekt und lässt sich so
implementieren, dass eine Laufzeit von O(xyz + p) erreicht wird, wobei
•
x = |V[L(1)] ∩ V[H]| sei,
•
y = |V[L(2)] ∩ V[H]| sei,
•
z = z(1) + zH + z(2) und z(1) die Dauer (obere Schranke) der Berechnung einer
kürzesten Distanz δ L(1) , zH die Dauer (obere Schranke) der Berechnung einer
kürzesten Distanz δ H , z(2) die Dauer (obere Schranke) der Berechnung einer
kürzesten Distanz δ L( 2 ) sei,
•
ρ = ρ (1) + ρ H + ρ (2) und ρ (1) die Dauer (obere Schranke) eines kürzesten Weges in
L(1), ρ H die Dauer (obere Schranke) der Berechnung eines kürzesten Weges in H,
ρ (2) die Dauer (obere Schranke) der Berechnung kürzesten Weges in L(2) sei.
Beweis:
Zur Korrektheit überlegen wir uns Folgendes:
Falls es keinen kürzesten Weg zwischen i und j in N gibt, dann wird vom Algorithmus „[],
∞“ ausgegeben, weil L(1), L(1) und H Straßenunternetze von N sind und demnach keine
neuen Wege darin über die Zugänge enthalten sein können.
Falls j von i aus erreichbar ist, dann gilt für einen kürzesten Weg Punkt (4) oder (5).
Falls L(1) = L(2) bzw. f(i) = f(j), dann folgt die Korrektheit direkt aus Punkt (5) der
Definition der Einteilung eines Straßennetzes in Subnetze.
Ansonsten gilt nach der Definition für einen kürzesten Weg Punkt (4) a), b) oder c):
57
Falls a) gilt, dann wird dieser kürzeste Pfad im Rumpf der if-Anweisung „if j∈L(1)“
gefunden und zurückgegeben.
Falls b) gilt, dann wird dieser kürzeste Pfad in den beiden verschachtelten for-Schleifen
bei a = e = d gefunden und später zurückgegeben.
Im Fall c) wird dieser Pfad in den beiden verschachtelten for-Schleifen bei einem
bestimmten Paar (a, e) gefunden und später zurückgegeben.
Die Laufzeit kommt folgendermaßen zustande:
Für den Fall L(1) = L(2) gilt die Schranke wegen des additiven p sicherlich. Der if-Teil „if
j∈L(1)“ ist auch in dem additiven p enthalten, weil man mit einer kürzesten Weg auch die
kürzeste Distanz hat. Ansonsten:
Wenn man den Datenstrukturen der Low-Level-Subnetze z.B. jeweils eine verkettete Liste
mit den Zugängen zum High-Level-Subnetz (die Mengen V[L(1)] ∩ V[H]) hinzufügt (und
entsprechende Verpointerungen), dann kann man die ganzen Paare (a, e) in Zeit O(xy)
generieren. Für das Innere der beiden while-Schleifen braucht man offensichtlich jeweils
O(z) Zeit. Für die Rückgabe muss dann der ganze Pfad (und nicht nur die Länge)
berechnet bzw. zurück gegeben werden. Diese Zeit ist in dem ρ enthalten.
‫ڤ‬
Wir wissen nun, wie wir mit einer gegebenen Subnetz-Einteilung eines Straßennetzes
kürzeste Wege berechnen können. Aber wir wissen noch nicht, wie wir eine solche
Subnetz-Einteilung aus einem Straßennetz gewinnen können und welche Datenstrukturen
sich bei einer Implementierung für die Speicherung der Subnetze eignen, um gute
Resultate zu erhalten. Ersteres wollen wir im nächsten Abschnitt behandeln.
5.2 Herleitung der Straßensubnetze
In diesem Abschnitt wollen wir uns überlegen, wie wir „sinnvolle“ Subnetz-Einteilungen
zu einem gegebenen Straßennetz erhalten. Einfach irgendeine gültige Subnetz-Einteilung
zu erhalten ist nicht schwer, bringt aber nicht unbedingt viel. So kann man z.B. ein
Straßennetz N = (V, E, S, T, w, s, t) folgendermaßen in Subnetze „einteilen“: X := ({H},
{L}, f), wobei H = L = (V, E, S, T, w, s, t) und f(v) = L für alle v∈V. Diese Einteilung ist
wohl ziemlich nutzlos. Daher überlegen wir uns zuerst Kriterien, die es bei einer SubnetzEinteilung möglichst zu optimieren gilt, bevor wir auf einen konkreten Algorithmus, der
das dann mehr oder weniger gut macht, zu sprechen kommen.
58
5.2.1 Optimierungskriterien
Nun betrachten wir ein paar mögliche Optimierungskriterien bzw. Funktionen, die es bei
der Erstellung der Subnetze zu minimieren gilt. Bei diesen Optimierungsfunktionen geht
es immer um die Größe des für die Datenstrukturen der Subnetzaufteilung benötigten
Speicherplatzes oder um die (eher theoretische) Größe der Subnetze selbst, da diese an
sich schon wichtig sind und auch bei vielen Datenstrukturen mehr oder weniger direkt die
Laufzeitschranken
für
den
Algorithmus
HIERARCHISCHE_WEGBERECHNUNG
determinieren.
Jede dieser Optimierungskriterien definiert ein eigenes Optimierungsproblem, welches als
Eingabe ein Straßennetz N = (V, E, S, T, w, s, t) erwartet und dann eine Einteilung dessen
in Straßensubnetze X = ({H}, {L1, L2, ..., Lp}, f) in (hoffentlich) polynomieller Zeit liefert
und X dann das entsprechende Optimierungskriterium unter allen möglichen
Subnetzeinteilungen X’ von N minimiert.
Die meisten dieser Optimierungsprobleme bzw. Kriteriumsfunktionen haben kaum
praktischen Nutzen und sind nur da, um die Verständlichkeit dieses Themas durch ein
weiteres Beispiel zu fördern. Außerdem lässt sich an ihnen gut der Anstieg der
theoretischen Schwierigkeit der optimalen Lösung der jeweiligen Probleme erkennen. Wir
fangen mit den einfachen (und meistens praktisch wertlosen) Optimierungskriterien an und
arbeiten uns zu den komplexeren durch.
Zur Beschreibung der Optimierungskriterien benutze ich eine intuitive, formal vielleicht
nicht ganz saubere Notation: „Min! x“ bezeichne, dass es x zu minimieren gilt. Mit D(x)
meinen wir den Speicherplatzbedarf zur Speicherung von x mit den betrachteten
Datenstrukturen. Mit |x| meinen wir die (eher theoretische) Kardinalität, die sehr wohl von
D(x) asymptotisch abweichen kann. Im einzelnen bezeichnen wir mit |N| := |G| = |V| + |E|
1 für Straßennetze N = (V, E, S, T, w, s, t) (also auch Subnetze). Dadurch, dass sich (m.E.)
eigentlich immer Datenstrukturen für x mit Speicherplatzverbrauch O(|x|) finden lassen
(die dann vielleicht in anderer Hinsicht nicht unbedingt die effizientesten sind), ist D(x)
immer eine Verallgemeinerung von |x| (oder eher O(|x|) ).
Zu der Auswahl der Kriteriumsfunktionen und Bewertungen / Erläuterungen ist zu
bemerken, dass Straßennetze in der Regel sehr lichte (erweiterte) Graphen sind und
demnach die Anzahl der Kanten m asymptotisch in linearem Zusammenhang mit der
Anzahl der Knoten n stehen. Also gilt m = O(n) und demnach brauchen eben z.B.
Datenstrukturen, die solche Graphen bzw. Straßennetze mit den Kantenmengen als
verkettete Listen speichern, asymptotisch um Faktor n weniger Speicherplatz als
Datenstrukturen, welche die Kanten als Adjazenzmatrix speichern oder insbesondere
1 S, T, w, s, t lassen sich m.E. immer durch entsprechende Verpointerungen ohne zusätzlichen asymptotischen
Speicherplatzverbrauch in die Datenstrukturen zur Speicherung von N = (V, E, S, T, w, s, t) einbauen, weil sie
jeweils in linearem Zusammenhang mit |E| stehen.
59
Datenstrukturen, welche nebenbei noch eine (Variante der) Floyd-Wege-Matrix benutzen
(das werden wir später tun).
Kriteriumsfunktion (1): Min! |H| ( normalerweise = Min! D(H) )
Bei diesem Kriterium geht es darum, die Größe des High-Level-Subnetzes zu minimieren.
Dieses Problem ist leicht optimal lösbar, indem man das gegebene Straßennetz N z.B.
folgendermaßen in Subnetze „aufteilt“: X := ({H}, {L}, f), wobei H = (Ø, Ø, 0) und L = (V,
E, w) und f(v) = L für alle v∈V.
Hat diese Aufteilung von N in Subnetze praktischen Nutzen? Wohl kaum.
p
Kriteriumsfunktion (2): Min!
∑| L
i =1
i
|
Mit Kriterium möchte man die Gesamtgröße der Subnetze zu minimieren. Dieses Problem
ist auf die gleiche Weise optimal lösbar wie die Kriteriumsfunktion (1), weil jeder Knoten
zumindest einmal in einem Low-Level-Subnetz vorkommen muss und hierbei jeder
Knoten in genau einem Subnetz vorkommt.
Wie bei der Kriteriumsfunktion (1) fällt mir hier keine sinnvolle Anwendung ein, weil die
optimale Lösung nicht mehr viel mit einem hierarchischen Straßennetz zu tun hat.
p
Kriteriumsfunktion (3): Min!
∑ D( L )
i =1
i
Diese Kriteriumsfunktion sieht zwar sehr ähnlich aus wie (2), eine optimale Lösung
hierfür kann aber je nach verwendeten Datenstrukturen von einer optimalen Lösung für (2)
abweichen. Dies kommt daher, dass aus der Mathematik z.B. folgendes bekannt ist: (a +
b)2 > a2 + b2 für a, b∈ Ν , aber (a + b)1 = a1 + b1. Deshalb werden hier normalerweise bei
optimalen Lösungen bei Verwendung von Datenstrukturen, deren Komplexität quadratisch
in n ist, die Gesamtknoten ungefähr gleich auf die einzelnen Subnetze verteilt sein. Dies
muss aber bei Kriteriumsfunktion (2) überhaupt nicht so sein, sondern es zählt nur die
Gesamtzahl der Knoten (wenn die Kantenzahl linear in n ist, was wir bei Straßennetzen,
wie gesagt, normalerweise annehmen können).
Bei Datenstrukturen, die in n lineare Komplexität haben, ist die optimale Lösung hierfür
gleich der von Funktion (2) und hat kaum praktischen Nutzen.
Mir ist kein polynomieller Algorithmus bekannt, der für Datenstrukturen mit in n
quadratischer Komplexität bzgl. dieser Kriteriumsfunktion optimale Lösungen generiert.
Ohne die Beachtung von H macht diese Kriteriumsfunktion aber auch nicht viel Sinn.
60
p
Kriteriumsfunktion (4): Min!
∑| L
i =1
i
| + |H|
Dieses Kriterium lässt sich auf die gleiche Weise optimal lösen wie die Funktionen (1) und
(2) und leider auch mit dem gleichen, geringen praktischen Nutzen.
p
Kriteriumsfunktion (5): Min!
∑ D( L ) + D(H)
i =1
i
Wie bei Funktion (3) ist mir hierzu auch kein polynomieller Algorithmus zur Bestimmung
optimaler Lösungen bei Datenstrukturen mit in n quadratischer Komplexität bekannt. Eine
Einteilung eines Straßensubnetzes, die dies minimiert, hat aber praktische Relevanz, weil
sie minimalen Speicherplatz benötigt.
Kriteriumsfunktion (6): Min! max{| Li | + | L j | + | H |}
i , j ,i ≠ j
Für dieses Problem ist mir kein polynomieller Lösungsalgorithmus bekannt. Ein solcher
hätte aber praktischen Nutzen, weil man zu einer Wegberechnung mit dem Algorithmus
HIERARCHISCHE_ WEGBERECHNUNG zwei Low-Level-Subnetze benötigt und ein HighLevel-Subnetz und man durch dieses Kriterium den benötigten Speicherplatz für eine
Wegberechnung minimieren kann (eine Anwendung hierfür wäre z.B. auch ein auf
verschiedenen Prozessoren verteilt arbeitender Wegfindungs-Algorithmus). Außerdem ist
dieses Kriterium auch ein wenig mit Funktion (8) (positiv) korreliert.
Kriteriumsfunktion (7): Min! max{D( Li ) + D( L j ) + D( H )}
i , j ,i ≠ j
Wie bei (6) ist mir für diese Kriteriumsfunktion auch keine polynomieller
Lösungsalgorithmus bekannt und die praktische Relevanz ist hier sogar noch ein wenig
höher, weil diese Funktion allgemeiner ist.
p
Kriteriumsfunktion (8): Min!
∑ | V (L ) ∩ V (H ) |
i =1
i
p
Diese Kriteriumsfunktion minimiert die durchschnittliche Anzahl von Übergängen der
Low-Level-Subnetze ins High-Level-Subnetz. Der Nutzen liegt darin, dass die Anzahlen
der Übergänge direkt die Laufzeit des Algorithmus HIERARCHISCHE_ WEGBERECHNUNG
determinieren. Nebenbei wird eine Lösung, die diese Funktion minimiert auch eher
insgesamt „kleine“ Subnetze haben und somit in dieser Beziehung auch in die „Nähe“ der
Minima der Funktionen (6) bzw. (7) kommen.
61
Fazit:
Meiner Meinung nach sind die Funktionen (5) – (8) aus den schon beschriebenen Gründen
am sinnvollsten. Am „liebsten“ wäre mir ein (polynomieller) optimaler Algorithmus bzgl.
(8), (7) und (5), wobei die Kriterien in dieser Reihenfolge (lexikographisch) herangezogen
werden. Aber selbst ein solcher Algorithmus muss nicht immer wirklich gute Resultate
bzgl. Speicherplatzverbrauch und Laufzeiten bringen, da es vermutlich für unsere
Anwendung inhärent schlechte Straßennetze bzw. Graphen gibt. Diese dürften aber in der
Praxis (Straßennetze aus der Realität) kaum auftreten.
5.2.2 Heuristik: Landkreise und Autobahnunternetz als Grundlage für die Subnetze
In diesem Abschnitt wollen wir einen Algorithmus – genauer gesagt eine Heuristik –
herleiten, welcher, gegeben ein Straßennetz, immer eine (gültige) Einteilung dessen in
Subnetze generiert, die aber nicht unbedingt die im vorherigen Abschnitt aufgezählten
Optimierungskriterien erfüllt.
Dem Algorithmus zur Einteilung eines Straßennetzes in Subnetze liegt die Idee des
Grundmodells aus Abschnitt 5.1.1 zugrunde, von der wir uns ab 5.1.2 vorerst ein wenig
distanziert haben, indem wir die Low-Level-Subnetze und das High-Level-Subnetz ohne
direkten Bezug zu Straßennetzen und die vorhandenen Strukturen definiert haben.
Die Idee ist, die in einem Straßennetz schon vorkommende Hierarchie der Straßentypen
und die vom Staat, Land oder sonstiger Instanz bestimmten Verwaltungsbezirke wie z.B.
Landkreise als Grundlage für die Einteilung des Straßennetzes in Straßensubnetze zu
benutzen. Da diese vorläufige Einteilung wahrscheinlich gegen einige Punkte der
Definition der Einteilung eines Straßennetzes in Subnetze verstößt, muss diese noch
nachbearbeitet werden. Bevor wir auf diese Nachbearbeitung eingehen, betrachten wir
diese vorläufige Einteilung:
Sei N = (V, E, S, T, w, s, t) das zugrunde liegende Straßennetz. Der Einfachheit halber gebe
es nur folgende zwei Straßentypen: „Autobahnen“ und den Rest, den wir als
„Landstraßen“ bezeichnen, also T = {Autobahn, Landstraße} 1. Sei P = {P1, P2, ..., P|P|}
die Menge der Landkreise (oder sonstige Verwaltungsbezirke) der N zugrunde liegenden
1 Das ganze Verfahren lässt sich natürlich auch in mehr Dimensionen hierarchisch organisieren, was auch (vermutlich)
sehr sinnvoll sein kann. Darauf werde ich im Ausblick noch einmal kurz eingehen. Eine Hierarchie in 5 Ebenen
könnte bzgl. der Straßen z.B. so aussehen: eine Ebene / Level mit 30’er Zonen, ein Level Straßen in Städten, ein
Level Landstraßen, ein Level Bundesstraßen, ein Level Autobahnen. Diese Diplomarbeit betrachtet aber nur die
einfachere Variante mit zwei Ebenen (die auch schon genug Schwierigkeiten beinhaltet).
62
„Karte“1. Dazu gebe es eine Funktion g: V → P, welche jeden Knoten zu (genau) einem
Landkreis zuordnet. P ist also eine Partitionierung der Knotenmenge (man kann demnach
hierfür eine beliebige Partitionierung von V nehmen).
Aus N, P und g möchten wir nun eine Einteilung von N in Subnetze X = ({H}, {L1, L2, ...,
Lp}, f) mit p = |P| erhalten. Ein vorläufiges High-Level-Subnetz H erhalten wir dadurch,
dass wir H als das Autobahnunternetz von N definieren (siehe Kapitel 4.4). Alternativ
dazu kann man auch das durch den Algorithmus AUTOBAHNNETZ_ERWEITERUNG
erweiterte Autobahnnetz nehmen, ist aber nicht unbedingt erforderlich und auch nicht
unbedingt vorteilhaft (dazu später mehr). Die Low-Level-Subnetze Li, 1 ≤ i ≤ p definieren
wir vorläufig folgendermaßen: Li := (V[Li], E[Li], S[Li], T[Li], w[Li], s[Li], t[Li]), wobei
V[Li] := {v∈V | g(v) = Pi}, E[Li] := Ø, S[Li] := die Nullfunktion 0, T[Li] := {Autobahn,
Landstraße}, und w[Li], s[Li] und t[Li] jeweils als die Nullfunktion 0. g definieren wir
(natürlich) gleich f.
Was fehlt jetzt noch? Diese Einteilung von N in Subnetze erfüllt offensichtlich die Punkte
(1) bis (3) der Definition zur Einteilung eines Straßennetzes in Subnetze. Die Punkte (4)
und (5) dagegen sind im Allgemeinen nicht erfüllt, da z.B. keines der Low-Level-Subnetze
irgendwelche Kanten enthält. Nun gehen wir folgendermaßen im Algorithmus vor: Wir
betrachten alle kürzesten Pfade und sorgen lokal bei jedem einzelnen Pfad dafür, dass
dieser die Punkte (4) und (5) der Definition erfüllt.
Dazu betrachten wir nun eine Klassifikation von möglichen Fällen für (kürzeste) Pfade
und überlegen uns bei jedem einzelnen Fall, wie man diesen im Falle eines Verstoßes
gegen Punkt (4) oder (5) der Definition erfüllen kann:
Hierzu betrachten wir einen kürzesten Pfad P = [v0, e1, v1, e2, ..., vk-1, ek, vk] von v0 zu vk.
Bzgl. dieses Pfades bezeichne x den maximalen Index, so dass vx ∈ V[f(v0)] und y den
minimalen Index, so dass vy ∈ V[f(vk)]. Ferner bezeichne a∈{x, ..., y} den minimalen
Index, so dass va ∈ V[H], falls es so ein a gibt und sonst a := -1 und b∈{x, ..., y} den
maximalen Index, so dass vb ∈ V[H], falls es so ein b gibt und sonst b := -1.
1 Karte ist hier intuitiv zu verstehen. An kaum einer Stelle der Diplomarbeit gehen wir auf Einbettungen von Graphen in
die Ebene ein (siehe z.B. A*-Algorithmus), Topologie oder sonstiges. Zum Teil könnte deren Beachtung zwar
vielleicht sinnvoll sein, würde aber den Rahmen dieser Diplomarbeit sprengen.
63
Fall 1: x = k (dies ist äquivalent zu vk ∈ V[f(v0)])
vk liegt also im Stamm-Subnetz von v0. Siehe Abb. 14.
Fall 1 a: Für alle i∈{0, ..., k} gilt: vi ∈ V[f(v0)] und für alle i∈{1, ..., k} gilt: ei ∈ E[f(v0)]
Der ganze kürzeste Pfad von v0 nach vk liegt also im Stammsubnetz von v0. Dieser Fall
erfüllt Punkt (5) oder Punkt (4) a) der Definition.
Fall 1 b: ¬ Fall 1 a)
Dieser Fall verstößt gegen Punkt (5) oder Punkt (4) a). Dieser Verstoß lässt sich aber leicht
dadurch beheben, dass man alle Knoten und Kanten von P zum Subnetz f(v0) hinzufügt.
f(v0)
v0
f(v0)
v0
vk
vk
Abb. 14: Beispiel Fall 1 a, Fall 1 b. Links sieht man eine Skizze für den Fall 1 a) und rechts eine für den
Fall 1 b)
64
Fall 2: x < k und a = x und b = y
Es gibt also ein Stück Autobahn (und wenn auch nur ein einzelner Knoten oder ein oft
unterbrochenes Stück) zwischen dem Stammsubnetz von v0 und dem Stammsubnetz von
vk. Damit dieser Fall nicht gegen Punkt (4) c) verstößt, muss Folgendes gelten (die
Unterfall-Kombinationen sind hier zu viele um aufzuzählen):
a) Für alle 0 ≤ i ≤ a: ei ∈ E[f(v0)] (und dadurch natürlich auch vi ∈ V[f(v0)]), sprich,
das erste Stück bis zum Index a muss vollständig zu f(v0) gehören.
b) Für alle a < i ≤ b: ei ∈ E[H], also das Stück zwischen a und b muss vollständig zu
H gehören.
c) Für alle b < i ≤ k: ei ∈ E[f(v0)], also das letzte Wegstück (ab Index b) muss
vollständig zum Stammsubnetz von vk gehören.
Falls obige Bedingungen nicht erfüllt sind, kann man sie durch einfaches Hinzufügen von
den entsprechenden Knoten und Kanten zu den jeweiligen Subnetzen erfüllen. Siehe Abb.
15.
f(v0)
v0
vx = va
f(vk)
vy = vb
vk
f(v0)
v0
vx = va
f(vk)
vy = vb
vk
Abb. 15: Beispiel Fall 2. Oben sieht man den Fall 2, wo die Punkte a), b) und c) verletzt sind. Unten
sieht man den die Korrektur, bei der a), b) und c) nach dem Hinzufügen von Knoten und
Kanten zu den entsprechenden Subnetzen erfüllt sind. Die blauen und roten Kanten zusammen
stellen den kürzesten Weg von v0 nach vk dar. Die blauen Kanten bezeichnen hierbei
Landstraßen-Kanten und die roten Autobahn-Kanten. Die farbigen Flächen skizzieren jeweils
die Stammsubnetze vom Startknoten und Zielknoten des aktuellen Pfades.
65
Fall 3: x < k und a > x und b = y
Dieser Fall ist wie Fall 2, nur beginnt das (eventuell nur aus einem Knoten bestehende
oder lückenhafte) Autobahnstück außerhalb des Stammsubnetzes von v0. Damit dieser Fall
nicht gegen Punkt (4) c) verstößt, erweitern wir das Stammsubnetz von v0 um die Knoten
und Kanten von vx bis vk und beseitigen Lücken innerhalb der drei Wegteile. Formal
ausgedrückt, sorgen wir wieder dafür, dass die drei Punkte a), b) und c) von Fall 2 erfüllt
sind, nur ist dieses Mal a > x: (Siehe Abb. 16.)
a) Für alle 0 ≤ i ≤ a: ei ∈ E[f(v0)] (und dadurch natürlich auch vi ∈ V[f(v0)]), sprich,
das erste Stück bis zum Index a muss vollständig zu f(v0) gehören.
b) Für alle a < i ≤ b: ei ∈ E[H], also das Stück zwischen a und b muss vollständig zu
H gehören.
c) Für alle b < i ≤ k: ei ∈ E[f(v0)], also das letzte Wegstück (ab Index b) muss
vollständig zum Stammsubnetz von vk gehören.
Dass wir das Stammsubnetz von v0 erweitern ist Willkür. Wir könnten ebenso das
Autobahnstück verlängern, so dass dessen erster Knoten vx ist. Aber wahrscheinlich ist es
meistens besser – so wie wir es getan haben – das Stammsubnetz zu erweitern, weil sonst
das High-Level-Subnetz zu groß werden würde (und das High-Level-Subnetz ist später an
fast jeder kürzesten-Weg-Berechnung beteiligt).
66
f(v0)
v0
vx
f(vk)
va
vy = vb
vk
f(v0)
v0
f(vk)
va = vx
vy = vb
vk
Abb. 16: Beispiel Fall 3. Oben sieht man den Fall 3, wo die Punkte a), b) und c) verletzt sind. Unten
sieht man den die Korrektur, bei der a), b) und c) nach dem Hinzufügen von Knoten und
Kanten zu den entsprechenden Subnetzen erfüllt sind. Die blauen und roten Kanten zusammen
stellen den kürzesten Weg von v0 nach vk dar. Die blauen Kanten bezeichnen hierbei
Landstraßen-Kanten und die roten Autobahn-Kanten. Die farbigen Flächen skizzieren jeweils
die Stammsubnetze vom Startknoten und Zielknoten des aktuellen Pfades.
Fall 4: x < k und a = x und b < y
Dieser Fall ist wie Fall 2, nur endet das (eventuell nur aus einem Knoten bestehende oder
lückenhafte) Autobahnstück echt vor dem Stammsubnetzes von vk. Damit dieser Fall nicht
gegen Punkt (4) c) verstößt, erweitern wir das Stammsubnetz von vk um die Knoten und
Kanten von vb bis vy und beseitigen eventuelle Lücken in den Wegteilen. Formal
ausgedrückt, sorgen wir wieder dafür, dass die drei Punkte a), b) und c) von Fall 2 erfüllt
sind, nur ist dieses Mal b < y. Siehe Abb. 17.
Wie in Fall 3 ist diese Art der Erweiterung der Subnetze nicht die einzig mögliche, um
diesen Pfad die Punkte (4) und (5) erfüllen zu lassen, aber die intuitiv naheliegenste und
vermutlich meistens auch günstigste Variante.
67
f(v0)
f(vk)
v0
vb
vx = va
vy
vk
f(v0)
f(vk)
v0
vy = vb
vx = va
vk
Abb. 17: Beispiel Fall 4. Oben sieht man den Fall 4, wo die Punkte a), b) und c) verletzt sind. Unten
sieht man den die Korrektur, bei der a), b) und c) nach dem Hinzufügen von Knoten und
Kanten zu den entsprechenden Subnetzen erfüllt sind. Die blauen und roten Kanten zusammen
stellen den kürzesten Weg von v0 nach vk dar. Die blauen Kanten bezeichnen hierbei
Landstraßen-Kanten und die roten Autobahn-Kanten. Die farbigen Flächen skizzieren jeweils
die Stammsubnetze vom Startknoten und Zielknoten des aktuellen Pfades.
Fall 5: x < k und a > x und b < y
Dieser Fall enthält im Prinzip Fall 3 und 4, denn das Autobahnstück beginnt zu spät und
endet zu früh. Damit dieser Fall nicht gegen Punkt (4) c) verstößt, erweitern wir beide
Stammsubnetze und beseitigen sonstige Lücken. Formal ausgedrückt, sorgen wir wieder
dafür, dass die drei Punkte a), b) und c) von Fall 2 erfüllt sind, nur ist dieses Mal a > x und
b < y. Siehe Abb. 18.
Wie in den anderen Fällen ist dies nicht die einzige Korrekturmöglichkeit.
68
f(v0)
f(vk)
v0
vx
vb
va
vy
vk
f(v0)
v0
f(vk)
va = vx
vb = vy
vk
Abb. 18: Beispiel Fall 5. Oben sieht man den Fall 5, wo die Punkte a), b) und c) verletzt sind. Unten
sieht man den die Korrektur, bei der a), b) und c) nach dem Hinzufügen von Knoten und
Kanten zu den entsprechenden Subnetzen erfüllt sind. Die blauen und roten Kanten zusammen
stellen den kürzesten Weg von v0 nach vk dar. Die blauen Kanten bezeichnen hierbei
Landstraßen-Kanten und die roten Autobahn-Kanten. Die farbigen Flächen skizzieren jeweils
die Stammsubnetze vom Startknoten und Zielknoten des aktuellen Pfades.
Fall 6: x < k und a = -1
In diesem Fall (siehe Abb. 19) gibt es kein Autobahnstück zwischen dem Stammsubnetz
von v0 und dem Stammsubnetz von vk. Wir könnten nun z.B. das Wegstück zwischen vx
und vy zum High-Level-Subnetz hinzufügen, aber meistens ist es wahrscheinlich
sinnvoller, dieses Stück zum Stammsubnetz von v0 hinzu zu fügen (oder alternativ zum
Stammsubnetz von vk) und nur den Knoten vy zum High-Level-Subnetz hinzuzufügen, um
das High-Level-Subnetz, welches bei fast jeder kürzesten-Weg-Berechnung benötigt wird,
69
nicht zu groß werden zu lassen. Also formal ausgedrückt, sorgen wir dafür, dass Folgendes
erfüllt ist:
a) Für alle 0 ≤ i ≤ y: ei ∈ E[f(v0)] (und dadurch natürlich auch vi ∈ V[f(v0)]), sprich,
das erste Stück bis zum Index a muss vollständig zu f(v0) gehören.
b) Der Punkt vy gehört zu V[H].
c) Für alle y < i ≤ k: ei ∈ E[f(v0)], also das letzte Wegstück (ab Index b) muss
vollständig zum Stammstubnetz von vk gehören.
f(v0)
v0
vx
f(vk)
vk
vy
f(v0)
v0
f(vk)
vy = vx
vk
Abb. 19: Beispiel Fall 6. Oben sieht man den Fall 2, wo die Punkte a), b) und c) verletzt sind. Unten
sieht man den die Korrektur, bei der a), b) und c) nach dem Hinzufügen von Knoten und
Kanten zu den entsprechenden Subnetzen erfüllt sind. Die blauen und roten Kanten zusammen
stellen den kürzesten Weg von v0 nach vk dar. Die blauen Kanten bezeichnen hierbei
Landstraßen-Kanten und die roten Autobahn-Kanten. Die farbigen Flächen skizzieren jeweils
die Stammsubnetze vom Startknoten und Zielknoten des aktuellen Pfades.
Wir können also die gegen die Punkte (4) und (5) der Definition einer Einteilung eines
Straßennetzes in Subnetze verstoßenden Fälle 1 b), 2 zum Teil, 3, 4, 5 und 6 lokal bei
einem betrachteten Pfad P korrigieren, indem wir das Stamm-(Low-Level-)Subnetz des
Startknotens von P, das Stamm-(Low-Level-)Subnetz des Zielknotens von P und das
High-Level-Subnetz um Knoten und Kanten von P erweitern. Hat diese lokale Korrektur
Einfluss auf andere (nicht gegen die Punkte (4) und (5) verstoßende) Pfade P’ in N bzw X?
Höchstens positiven, d.h. es kann passieren, dass dadurch ein Pfad P’, der vorher gegen
70
(4) und (5) verstoßen hat, nun nicht mehr gegen diese Punkte der Definition verstößt (dies
dürfte z.B. „häufig“ bei Pfaden P’, die P als echten Teilpfad enthalten, auftreten). Vorher
nicht gegen (4) und (5) verstoßende Pfade bleiben „sauber“.
Durch die bisherigen Überlegungen haben wir den Algorithmus vollständig hergeleitet und
auch schon zum großen Teil bewiesen. Nachfolgend der zusammen fassende Pseudocode
des Algorithmus:
Algorithmus: SUBNETZ_EINTEILUNGS_GENERIERUNG
Eingabe: a) ein Straßennetz N = (V, E, S, T, w, s, t) mit V = {1, ..., n}
b) eine Menge von Landkreisen (Landkreis-Objekte) von N {P1, P2, ..., P|P|}
c) ein Unterstraßennetz A von N (das Autobahnunternetz von N), eventuell
vorbearbeitet mit dem Algorithmus AUTOBAHNNETZ-ERWEITERUNG
d) eine Funktion g: V → {P1, ...., P|P|}
Ausgabe: eine Einteilung von N in Straßensubnetze X = ({H}, {L1, L2, ..., L|P|}, f)
Methode:
// Initialisiere die vorläufigen Low-Level-Subnetze, High-Level-Subnetz und f
p := |P|;
for i := 1 to p
do
V[Li] := {v∈V | g(v) = Pi};
E[Li] := Ø;
S[Li] := Ø;
T[Li] := {Autobahn, Landstraße};
w[Li] := 0;
s[Li] := 0;
t[Li] := 0;
od
H := A;
f := g;
// Eigentlicher Algorithmus
for i := 1 to n
do
for j := 1 to n, j ≠ i
do
betrachte den kürzesten Pfad P von i nach j in N;
k := der Fall von P gemäß obiger Klassifizierung bzgl. N und
Xcur := ({H}, {L1, L2, ..., Lp}, f);
Behandele Fall k wie oben angegeben bzgl. P, N, Xcur, also füge H, f(i) und
f(j) die beim Fall k angegebenen Knoten, Kanten, Straßen aus P hinzu
und erweitere w[Li], s[Li] und t[Li] entsprechend;
od
71
od
X := ({H}, {L1, L2, ..., Lp}, f);
return X;
‫ڤ‬
Die wichtigesten Punkte der Korrektheit des Algorithmus haben wir uns schon überlegt,
fassen diese aber nochmal prägnant in folgendem Satz mit einer Laufzeitanalyse
zusammen:
Lemma 11:
Der Algorithmus SUBNETZ-EINTEILUNGS-GENERIERUNG ist korrekt und lässt sich so
implementieren, dass eine Laufzeit von O(n3) erreicht wird.
Beweis:
Bei der Korrektheit ist zu zeigen, dass am Ende für das zurückgegebene Tupel X die
Punkte (1) – (5) der Definition einer Einteilung eines Straßennetzes in Subnetze erfüllt
sind.
Die Punkte (1) – (3) sind offensichtlich erfüllt.
Die Punkte (4) und (5) sind aus folgenden zwei Gründen erfüllt: Zum einen betrachten wir
jeden kürzesten Pfad innerhalb N (genau) einmal und falls ein solcher Pfad zum Fall 3, 4,
5 oder 6 gehört und damit gegen Punkt (4) oder (5) verstößt, erweitern wir die Subnetze
immer derart, dass dieser Verstoß danach nicht mehr vorliegt (dies kann man in jedem
einzelnen Fall der vollständigen Fallunterscheidung auf triviale Art und Weise
überprüfen). Zum anderen kann es (natürlich) nicht passieren, dass eine Erweiterung eines
Subnetzes bei der Bearbeitung eines kürzesten Pfades P für einen anderen kürzesten Pfad
P’, der vor der Erweiterung die Punkte (4) und (5) erfüllt hat, danach die Punkte (4) und
(5) nicht mehr erfüllt.
Auf eine Laufzeit von O(n3) kommen wir z.B. durch folgende (hier nur skizzierte)
Implementierung:
Die Kantenmenge E von N wird repräsentiert durch Adjazenzlisten und N ist ansonsten
bzgl. V, E, S, T, s, t hinreichend verpointert.
Es gibt zu jedem Knoten und zu jeder Kante in N ein Array von Pointern auf die Subnetze
(also hat das Array eine Größe von p+1) derart, dass v.SubnetzRef[SubnetzNr] = null ⇔ v
kommt nicht im Subnetz mit der Nummer SubnetzNr vor und v.SubnetzRef[SubnetzNr] = x
≠ null ⇔ x ist Referenz auf den Knoten (besser gesagt, die Knotenkopie von) v im
Subnetz mit der Nummer SubnetzNr. Dies ermöglicht uns, jeweils in O(1) zu überprüfen,
ob eine bestimmte Kante oder Knoten schon in einem Subnetz vorkommt oder eine
Referenz auf diesen Knoten / Kante zu bekommen. Die Zeit für die Initialisierung dieser
Verpointerungen fällt asymptotisch nicht ins Gewicht.
72
Vor Ablauf des eigentlichen Algorithmus wird eine Floyd-Wege-Matrix berechnet (die
hinreichend mit N verpointert wird), welche dann die kürzesten Wege speichert. Dies ist in
Zeit O(n3) möglich.
Durch die Floyd-Wege-Matrix bekommt man dann jeden kürzesten Pfad P (alle Knoten
und Kanten) im Inneren der beiden while-Schleifen in Zeit O(|P|) 1. Durch die
Verpointerungen können wir innerhalb von O(|P|) Zeit herausfinden, zu welchem Fall der
aktuelle Pfad gehört und in nochmal O(|P|) Zeit die Subnetze entsprechend erweitern
(durch die Verpointerungen sollte das Hinzufügen einer Kante oder eines Knotens in
einem Subnetz jeweils nur O(1) Zeit in Anspruch nehmen)2. Also brauchen wir für die
Überprüfungen aller Pfade insgesamt O(n2 α) = O(n3) Zeit, wobei α die durchschnittliche
ungewichtete Länge eines kürzesten Pfades in N ist.
Insgesamt dominiert hier also das O(n3) der Anwendung des Algorithmus von Floyd.
‫ڤ‬
Was wir noch nicht angesprochen haben ist, ob bzw. was uns eine Vorbearbeitung des
Autobahnunternetzes mit dem Algorithmus AUTOBAHNNETZ_ERWEITERUNG bringt. Eine
erste Beobachtung dazu ist, dass es trotz Vorbearbeitung des Autobahnunternetzes
passieren kann, dass das Autobahnnetz noch weiter im Algorithmus
SUBNETZ_EINTEILUNGS_GENERIERUNG erweitert werden muss, weil dieses nur
gegenüber den ursprünglichen Knoten des Autobahnunternetzes bzgl. kürzester Wege
abgeschlossen ist 3. Siehe dazu Abb. 20:
Man sieht, dass bei Verwendung von dem Algorithmus AUTOBAHNNETZ_ERWEITERUNG
vor Algorithmus SUBNETZ_EINTEILUNGS_GENERIERUNG das resultierende High-LevelSubnetz immer größer oder gleich groß ist, als wenn man das Autobahnsubnetz zuvor
nicht mit dem Algorithmus AUTOBAHNNETZ_ERWEITERUNG vorbearbeitet. Andersherum
ist es aber denkbar, dass die Low-Level-Subnetze durch ein etwas größeres High-LevelSubnetz deutlich kleiner sind. Im Abschnitt „Güte der Heuristik“ sind zwei (konstruierte)
Beispiele zu sehen, wo sich einmal die Verwendung von AUTOBAHNNETZ_ERWEITERUNG
lohnt und das andere mal ungünstig ist.
1 Da wir hier jeden Knoten und jede Kante auf Zugehörigkeiten zu den Subnetzen überprüfen müssen und eventuell zu
Subnetzen hinzufügen müssen, bringt uns hier die Variante der Floyd-Matrix nichts. Abgesehen davon, braucht
3
die Berechnung der Floyd-Matrix ohnehin schon O(n ) Zeit.
2 Natürlich lässt sich das auch alles auf einmal in O(|P|) machen.
3 Streng genommen könnte man in solchen Fällen natürlich auch die Low-Level-Subnetze erweitern. Dies dürfte
meistens aber eher ungünstig sein, vermute ich, weil diese dadurch sehr vergrößert werden können. Siehe Abb. ?
73
f(v0)
M
f(vk)
v0
vx = va
Q
vk
vy = vb
O
P
R
Abb. 20: Beispiel für Fall 2 nach AUTOBAHNNETZ_ERWEITERUNG. Die Autobahnstücke von M bis Q
und M bis R sind keine ursprünglichen, sondern sind im Verlauf des Algorithmus
AUTOBAHNNETZ_ERWEITERUNG entstanden, weil sie kürzeste Pfade zwischen M und Q bzw. R
sind. Weil O und P daher auch keine ursprünglichen Autobahnknoten sind, wird der kürzeste
Weg zwischen O und P nicht im Verlauf des Algorithmus AUTOBAHNNETZ_ERWEITERUNG zum
Autobahnnetz
hinzugefügt.
Dieser
muss
dann
noch
im
Algorithmus
SUBNETZ_EINTEILUNGS_GENERIERUNG zum High-Level-Subnetz hinzugefügt werden.
5.2.3 Güte der Heuristik
In diesem Abschnitt wollen wir ein paar Beispiele betrachten, um zu sehen, wie schlecht
die Heuristik SUBNETZ_EINTEILUNGS_GENERIERUNG sein kann. Die den Beispielen
zugrunde liegenden Straßennetze, die Partitionierung in Landkreise und die Auswahl des
Autobahnnetzes sind alle konstruiert. Daher werden wir nach Betrachtung der Beispiele
jeweils diskutieren, inwieweit solche Fälle bei realen Straßennetzen zu erwarten sind 1.
Es ist zu bemerken, dass dieser Abschnitt bei weitem keinen Anspruch auf Vollständigkeit
erhebt. Wir betrachten nicht die einzelnen Kriteriumsfunktionen aus Abschnitt 5.2.1 und
wie genau der Algorithmus SUBNETZ_EINTEILUNGS_GENERIERUNG diese erfüllt, sondern
es geht nur darum durch konstruierte Beispiele einzelne Schwächen des Algorithmus
aufzuzeigen und zu diskutieren, ob diese bei realen Straßennetzen in größerem Maße zu
erwarten sind. Hierzu ist im Zusammenhang mit Abschnitt 5.2.1 auch zu bemerken, dass
wir hier den Speicherplatzbedarf mit Hilfe der theoretischen Kardinalität bemessen und
keine konkreten Datenstrukturen für D(▪) betrachten.
Betrachten wir nun folgendes erste Beispiel, welches im Ggs. zu den darauf folgenden
noch sehr ausführlich und formal beschrieben ist (siehe die Abb. zum Verständnis):
Beispiel (1)
Sei N(z) := (V, E, S, T, w, s, t) das zugrunde liegende Straßennetz mit
1 Leider fehlte die Zeit, um die Heuristik anhand von realen Straßennetzen empirisch zu untersuchen. Dies ist sehr
schade, da bei Heuristiken solche Untersuchungen mit am wichtigsten ist.
74
•
V = {v1, v2, ..., vz, v’1, v’2, ..., v’z}
•
E = {(vi, vi+1), (vi+1, vi) | 1 ≤ i ≤ z} ∪ {(v’i, v’i+1), (v’i+1, v’i) | 1 ≤ i ≤ z} ∪ {(vz,
v’1)} ∪ {( v’1, vz)}
•
S = {A1},
•
T = {Autobahn},
•
w(e) = 1, s(e) = A1 für alle e∈E,
•
t(A1) = Autobahn
Betrachte nun folgende Auswahl der Partitionen / Landkreise und des vorläufigen HighLevel-Subnetzes / Autobahnnetz A:
•
P = {P1, ..., Pz} und g(vi) = Pi und g(v’i) = Pi,
•
A = N(z)
Wenn man auf diese Eingabe den Algorithmus SUBNETZ_EINTEILUNGS_GENERIERUNG
laufen lässt, ergibt sich eine Einteilung in Subnetze X = ({H}, {L1, L2, ..., Lz}, f) mit
•
f = g,
•
H = N(z),
•
Li = (V[Li], E[Li], S[Li], T[Li], w[Li], s[Li], t[Li]) für 1 ≤ i ≤ z mit
•
V[Li] = {vi, vi+1, ..., vz, v’1, v’2, ..., v’i},
•
E[Li] = {(vj, vj+1), (vj+1, vj) | i ≤ j ≤ z} ∪ {(v’j, v’j+1), (v’j+1, v’j) | 1 ≤ j ≤ i} ∪ {(vz,
v’1)} ∪ {( v’1, vz)}
•
S[Li], T[Li], w[Li], s[Li], t[Li]) analog zu den Funktionen in N (mit teilweise
eingeschränktem Definitionbereich).
Also gilt für alle i: |V[Li]| = z + 1 = n / 2 + 1 = O(n) und |E[Li]| = z = n / 2 = O(n).
Insgesamt ergibt sich wegen der Anzahl der Subnetze ein Speicherplatzbedarf von O(n2)
Ein einfaches (unhierarchisches) Speichern des Graphen geht in O(n). Oder wenn wir dem
dem Algorithmus anfangs n Paritionen, die jeweils einen Knoten enthalten, übergeben
hätten, wäre dies auch in O(n) möglich gewesen. Siehe Abb. 21:
v1
v2
vz-1
vz
v’1
v’2
v’z-1
v’z
Abb. 21: Abbildung für Beispiel 1. Hierzu ist zu bemerken, dass die einzelnen Farben die anfängliche
Partitionierung sichtbar machen. Am Ende gehört jeder Knoten und jede Kante zu jedem Highund Low-Level-Subnetz, was absolut unakzeptabel ist.
Hierzu gibt es folgendes zu bemerken und zu interpretieren:
75
Der Grund dafür, dass die Low-Level-Subnetze so groß werden, liegt in Punkt (5) der
Definition einer Einteilung eines Straßennetzes in Subnetze und diesbezüglich unsinnigen
Wahl der Partitionen in diesem Beispiel. Dieser Punkt (5) impliziert nämlich eine gewisse
Art von Konvexität bzgl. kürzester Wege innerhalb der Subnetze, die in diesem Beispiel
nicht gegeben ist.
Es fällt aber bei diesem Beispiel auf, dass gerade hier, wegen des großen High-LevelSubnetzes diese Konvexität eigentlich nicht notwendig ist, da man die Wege innerhalb des
Low-Level-Subnetzes auch über das High-Level-Subnetz berechnen kann.
Dementsprechend könnte man die Definition etwas abschwächen und den Algorithmus zur
Bestimmung kürzester Wege ein wenig verändern. Ich habe mich aber dagegen
entschieden, weil ich finde, dass zumindest jeweils ein kürzester Weg zwischen Knoten,
die das gleiche Stammsubnetz haben, in diesem Stammsubnetz enthalten sein soll.
Hauptgrund für das schlechte Abschneiden des Algorithmus in diesem Beispiel ist er aber
nicht unbedingt selber1, sondern eben die schlechte Eingabe der Partitionen. Bei
Landkreisen in realen Netzen z.B., an denen sich auch der Straßenbau ein wenig orientiert,
ist so etwas (hoffentlich) nicht zu erwarten.
Die folgenden Beispiele werden wir – im Interesse des Lesers – auf viel informellere und
intuitivere Weise betrachten und diese hauptsächlich anhand der Abbildungen erklären.
M.E. ist diese Darstellung aber immer noch eindeutig.
Beispiel (2)
Siehe Abb. 22 zu diesem Beispiel, welche das wieder von der Variable z abhängige
Straßennetz m.E. eindeutig definiert:
v’1
v’2
1
1
1
1
v1
30
v’z-1
1
1
v2
30
30
v’z
1
1
vz-1
30
vz
1 In gewisser Hinsicht natürlich schon, denn im Idealfall würde er ja gar nicht so eine Eingabe erwarten und einfach nur
durch die Eingabe eines Straßennetzes eine z.B. bzgl. der in Abschnitt 5.2.1 angegebenen Kriteriumsfunktionen
optimale Einteilung eines Straßennetzes in Subnetze herleiten.
76
Abb. 22: Abbildung für Beispiel 2. Hierzu ist zu bemerken, dass die einzelnen Farben die anfängliche
Partitionierung sichtbar machen. Die Zahlen an den Kanten entsprechen den Kanten-gewichten.
Rote Kanten gehören dem vorläufigen High-Level-Subnetz / Autobahnunternetz an und
schwarze nicht (sind vom Typ Landstraße).
Wenn man auf dieser Eingabe den Algorithmus SUBNETZ_EINTEILUNGS_GENERIERUNG
laufen lässt, ergibt sich wieder, dass jeder Knoten und jede Kante bis auf die AutobahnKanten zu jedem Low-Level-Subnetz gehört. Das Autobahnsubnetz bleibt so erhalten.
Dieses äußerst schlechte Ergebnis kommt wieder durch eine sehr schlechte Eingabe
zustande. Die Einteilung in Partitionen ist hier nicht unbedingt so ungünstig, aber dieses
Mal ist die Wahl des Autobahnunternetzes / High-Level-Subnetzes sehr schlecht, denn der
kürzeste Weg von vi nach vi+1 ist über die Landstraßen 10 mal kürzer als über Autobahn.
Wenn man statt dieser Autobahnkanten die Kanten zwischen den gestrichelten v – Knoten
nehmen würde (die in der Abbildung dazu parallelen Kanten), dann wäre die Einteilung
wohl bzgl. fast jeder halbwegs sinnvollen Kriteriumsfunktion viel besser.
Hier erweist sich hier die Vorbearbeitung des hier so ungünstigen Autobahnstücks mit
dem Algorithmus AUTOBAHNNETZ_ERWEITERUNG als nützlich. Durch diese wird das
High-Level-Subnetz zwar größer (es enthält dann alle Kanten und Knoten) – aber nicht
asymptotisch1 – aber die Low-Level-Subnetze bleiben so wie die vorläufige
Partitionierung und damit verringert sich der gesamte Platzbedarf asymptotisch um Faktor
n.
Beispiel (3)
Dieses Beispiel soll zeigen, dass die Verwendung der Vorbearbeitung des
Autobahnunternetzes sich auch in asymptotischer Größenordnung als negativ erweisen
kann: (siehe Abb. 23)
v1
v2
v3
vl
vl+1
vl+2
vl+3
vz-2
vz-1
vz
1 Man kann sich überlegen, dass das Autobahnnetz bei realen Straßennetzen wohl immer in linearem Zusammenhang
zum Gesamtstraßennetz steht. Es ist dann zwar vielleicht 100 mal kleiner, aber wenn man das Gesamtstraßennetz
um Faktor x vergrößert (Anzahl Knoten und Kanten) , dann wird wohl das Autobahnnetz auch in etwa um x
größer werden.
77
Abb. 23: Abbildung für Beispiel 3. In diesem Beispiel gibt es eine schwarz eingezeichnete Partition und
eine gelb eingezeichnete Partition zu Beginn des Algorithmus. Es gibt genau drei rot
eingezeichnete Autobahn-Kanten. Die restlichen z-4 Kanten sind alle vom Typ Landstraße.
Der Algorithmus AUTOBAHNNETZ_ERWEITERUNG generiert für diese Einteilung
unnötigerweise ein High-Level-Subnetz, welches alle Knoten und Kanten dieses BeispielGraphen enthält und demnach Komplexität von Θ(n) hat. Unnötigerweise deshalb, weil die
beiden Low-Level-Subnetze innerhalb sich selbst ja die kürzesten Wege ohne die
Erweiterung berechnen können und für die (kürzesten) Wege in das andere Subnetz ja das
eine, die beiden Low-Level-Subnetze verbindende Autobahnstück, ausreicht. Ohne die
Vorbearbeitung würde der Algorithmus SUBNETZ_EINTEILUNGS_GENERIERUNG ein
High-Level-Subnetz der Größe O(1) zurückgeben.
Warum ist gerade hier die Erweiterung des Autobahnnetzes um einen kürzesten Weg
zwischen zu Autobahn-Kanten inzidenten Knoten nachteilhaft? Der Grund dafür liegt
darin, dass hier nur zwei Low-Level-Subnetze da sind. Wäre „links“ von dem schwarzen
Subnetz noch ein derartig „1-dimensional“angelegtes Subnetz oder „rechts“ von dem
gelben,
dann
würde
das
Autobahnsubnetz
sowieso
vom
Algorithmus
SUBNETZ_EINTEILUNGS_GENERIERUNG so ähnlich erweitert werden.
Trotzdem sind natürlich auch in der Realität solche Fälle möglich, wenn auch wohl kaum
in dieser Größenordnung.
Beispiel (4)
Mit diesem Beispiel möchte ich zeigen, dass es auch bzgl. hierarchischer Datenstrukturen
oder zumindest bzgl. der von uns definierten Einteilung eines Straßennetzes in Subnetze
auch inhärent schlecht geeignete Eingabe-Graphen bzw. Straßennetze gibt: (siehe Abb.
24)
In diesem Beispiel besteht jeder kürzester Weg aus nur jeweils einer und – jedesmal einer
verschiedenen – Kante. Hier macht m.E. ein hierarchisches Verfahren ähnlich wie unseres
keinen Sinn.
Treten so ein Beispiel in der Praxis bei realen Straßennetzen auf? Nein. In realen
Straßennetzen würde schon allein aus Kostengründen wohl kaum für jedes Paar von
Knoten eine eigene Straße gebaut werden. Wir können eigentlich fast immer davon
ausgehen, dass in realen Straßennetzen die Anzahl der Kanten in linearer Relation mit der
Anzahl der Knoten steht.
78
v1
vz
v2
vz-1
v3
...
Abb. 24: Abbildung für Beispiel 4. In diesem Beispiel ist ein vollständiger Graph für die Knotenmenge
{v1, ..., vz} zu sehen. Jede Kante habe Gewicht von 1. Ich habe keine Partitionen und
Autobahnen eingezeichnet, weil sie hier definitiv keinen Sinn machen (siehe Text).
79
Beispiel (5)
Dieses letzte Beispiel soll zeigen, dass dieses hierarchische Verfahren auch wirklich
sinnvoll sein kann und stellt einen Best-Case dar. Das Straßennetz N(z) ist in der
folgenden Abb. (25) angegeben (c konstant):
v 1c −1
v 1c
v 22
v c2−1
v 12
v11
v12
vcz
v1z
v1z −1 v 2z −1
v cz−1
vcz −1
v 2z
vc2
vcz−−11
Abb. 25: Abbildung für Beispiel 5. In diesem Beispiel-Straßennetz N(z) gebe es z, hier farblich
gekennzeichnete, Partitionen. Es gibt genau z rot eingezeichnete Autobahn-Kanten und zc blau
eingezeichnete Landstraßenkanten. Insgesamt gibt es zc Knoten, wobei c konstant sei.
Nach Ausführung des Algorithmus SUBNETZ_EINTEILUNGS_GENERIERUNG besteht das
High-Level-Subnetz H aus den ursprünglichen z Autobahnkanten und die z Low-LevelSubnetze bestehen gemäß der Partitionierung aus jeweils c Knoten und c Kanten. Also hat
das High-Level-Subnetz Komplexität von O(z) und die z Low-Level-Subnetze jeweils
O(1).
Ich nehme an, dass dieser Fall in etwa dem Normalfall für reale Straßennetze
(entsprechend große) entspricht. Warum ich dies denke und was hieran so gut ist,
diskutieren wir in Abschnitt 5.3.2, wo wir zu dem Hauptergebnis dieser Diplomarbeit
kommen.
Fazit
Die ersten vier Beispiele haben gezeigt, dass der Algorithmus SUBNETZ_EINTEILUNGS
_GENERIERUNG bei eventueller Vorarbeit von dem Algorithmus AUTOBAHNNETZ
_ERWEITERUNG den benötigten Speicherplatz auf das quadratische vergrößern kann. In
den Diskussionen zu den einzelnen Beispielen sind wir zu dem Ergebnis gekommen, dass
solche Fälle bei Eingabe von realen Straßennetzen mit Verwaltungsstrukturen wie z.B.
Landkreise und dem eventuell vorbearbeiteten Autobahnunternetz zumindest eher selten
80
vorkommen. Es gibt gute Argumente dafür, dass der Best-Case normalerweise bei realen
Straßennetzen ungefähr eintritt, welche wir in Abschnitt 5.3.2 betrachten.
5.3 Verwendung der Variante der Floyd-Wege-Matrix
In Abschnitt 5.1 haben wir ein Verfahren kennengelernt, welches, gegeben eine Einteilung
eines Straßennetzes in Subnetze, kürzeste Wege berechnen kann. Im nachfolgenden
Abschnitt haben wir dann einen Algorithmus hergeleitet, der uns aus einem Straßennetz,
einer Menge von Verwaltungsbezirken des Straßennetzes – z.B. Landkreise – (bzw.
beliebige Straßenunternetze) und einem Autobahnnetz (bzw. beliebiges Straßenunternetz)
eine solche Unterteilung des Straßennetzes in Subnetze liefert. Bisher haben wir kaum die
Datenstrukturen zur Speicherung der Straßensubnetze betrachtet. Das und insbesondere
die Verwendung der Variante der Floyd-Wege-Matrix aus Kapitel 4 als Datenstruktur ist
Thema dieses Abschnitts.
5.3.1 Datenstrukturen
Was für Datenstrukturen kann man für die Speicherung der Straßensubnetze einer
Einteilung eines Straßennetzes N = (V, E, S, T, w, s, t) in Straßensubnetze X = ({H}, {L1,
L2, ..., Lp}, f) verwenden? Für unsere Zwecke im Prinzip alle, die es dem Algorithmus
HIERARCHISCHE_WEGBERECHNUNG ermöglichen zu laufen. Konkret muss jedes Subnetz
(sowohl High- als auch Low-Level) folgende Informationen zurückgeben bzw. berechnen
können:
•
(alle) kürzeste Wege zwischen Knoten des jeweiligen Subnetzes
•
(alle) kürzesten Distanzen δ(i, j) zwischen Knoten i, j aus dem jeweiligen Subnetz
Dazu müssen das High-Level-Subnetz und die Low-Level-Subnetze noch folgende
Informationen zurückgeben bzw. herleiten können:
•
welche Knoten in den jeweiligen Low-Level-Subnetzen bzw. in dem High-LevelSubnetz Zugänge in das High-Level-Subnetz bzw. die jeweiligen Low-LevelSubnetze sind, also die Mengen V[Li] ∩ V[H], 1 ≤ i ≤ p.
•
Die Zugänge müssen noch entsprechend verpointert bzw. entsprechende sonstige
Referenzen vorhanden sein (hier gibt es verschiedene Möglichkeiten), da in der
Praxis wohl ein Knoten u∈V[Li] ∩ V[H] durch zwei verschiedene Knoten v und
w repräsentiert wird mit v aus Li und w aus H und man in der Lage sein muss, aus
v w ermitteln zu können. Dies ist z.B. durch eine Referenz von Knoten v im LowLevel-Subnetz Li zum Knoten w im High-Level-Subnetz H möglich.
81
Im einfachsten Fall kann man die Subnetze wie gerichtete Graphen mit den Kanten als
Adjazenzlisten in den Knoten speichern1 und dazu noch Datenstrukturen für die Zugänge
von den Low-Level-Subnetzen zum High-Level-Subnetz und umgekehrt (ähnlich wie für
die Variante der Floyd-Wege-Matrix, s.u.) verwenden. Zur Ermittlung der kürzesten
Wege innerhalb der Subnetze kann man dann z.B. den Algorithmus von Dijkstra
verwenden.
Wir wollen nun als Datenstruktur für die Speicherung der Subnetze die Variante der
Floyd-Wege-Matrix aus Kapitel 4 benutzen. Um die folgenden Ausführungen
unmissverständlich auf den Punkt zu bringen, werden wir jetzt zum Teil auf eine
niedrigere Abstraktionsebene – von der bisher zum größten Teil konzeptuellen Ebene nun
in die Nähe der Implementationsebene – übergehen. Folgende Implementierung der
Datenstrukturen werden wir im Rest dieses Kapitels 5 betrachten:
Wie zuvor sei N = (V, E, S, T, w, s, t) das zugrunde liegende Straßennetz und X = ({H},
{L1, L2, ..., Lp}, f) eine Einteilung von N in Straßensubnetze.
Jedes Subnetz (sowohl high- als auch low-level) Li = (V[Li], E[Li], S[Li], T[Li], w[Li], s[Li],
t[Li]) sei folgendermaßen in einer Implementation repräsentiert:
•
wie ein „normaler“ gewichteter, gerichteter Graph Gi := (V[Li], E[Li], w[Li]) mit
der Kantenmenge E[Li] als Adjazenzlisten der Knoten
•
die Mengen bzw. Funktionen S[Li], T[Li], s[Li], t[Li] seien in der Implementierung
des obigen Graphen Gi irgendwie „eingebaut“ bzw. verpointert, so dass man in
O(1) Zeit bestimmen kann, welcher Straße eine Kante angehört und was für einen
Straßentyp eine bestimmte Straße hat.
•
der Variante der Floyd-Wege-Matrix Π’, die alle kürzesten Wege innerhalb von
Li speichert und diese speichere zusätzlich in jedem Matrix-Eintrag πij neben dem
k (siehe Kapitel 4) noch eine Referenz auf die Kante auf dem kürzesten Weg von
i nach j direkt vor k und die Kante direkt nach k, falls diese exisitieren und nil
sonst
•
einer Floyd-Distanz-Matrix D, welche alle kürzesten Distanzen δ(i, j) für i, j∈ Li
speichert
Zusätzlich enthalte jedes Low-Level-Subnetz Li = (V[Li], E[Li], S[Li], T[Li], w[Li], s[Li],
t[Li]) eine Datenstruktur, welches ihr ermöglicht, alle |V[Li] ∩ V[H]| Zugänge zum HighLevel-Subnetz H in O(|V[Li] ∩ V[H]|) Zeit zu bestimmen und in jeweils O(1) Zeit auch
eine Referenz zum entsprechenden Knoten im High-Level-Subnetz zu erhalten.
1 Hierbei und müssen natürlich noch die gegenüber (normalen) gerichteten Graphen zusätzlichen Informationen von
Straßennetzen eingebaut werden, also S, T, s, t. Dies dürfte aber in den meisten Fällen eher trivial sein.
82
Analog enthalte das High-Level-Subnetz eine Datenstruktur, welche die Zugänge zu den
Low-Level-Subnetzen speichert, so dass diese jeweils in O(1) inkl. Referenz auf den
jeweils entsprechenden Low-Level-Knoten ermittelt werden können.
Zudem sei für jeden Knoten v∈V klar (in O(1) Zeit), zu welchem Stamm-Subnetz es
gehört (also die Funktion f sei irgendwie in das Gesamt-Straßennetz eingebaut). Welche
Möglichkeiten gibt es dafür? Ein Array wäre eine Möglichkeit und Hashing eine andere.
Im ersten Fall benötigt man Θ(n) Speicherplatz und bei der zweiten Möglichkeit weniger
(abhängig von dem verwendeten Verfahren), aber die Zugriffszeiten sind nur noch im
Erwartungswert über eine Menge von Zugriffen konstant. Im weiteren Verlauf betrachten
wir der Einfachheit halber nur die Array-Variante, weil diese auch schon sehenswerte
Resultate bringt.
Außerdem muss im Subnetz herausfindbar sein, ob bei einer kürzeste-Weg-Anfrage der
Zielknoten j im Stammsubnetz f(i) des Startknotens i enthalten ist. Dies geht einfach
Überprüfung aller Knoten in f(i). Zumindest erhofften best-case stellt dies keinen
asymptotischen Overhead gegenüber komplizierteren Möglichkeiten wie z.B. Hashing dar.
Man sieht, dass diese Beispiel-Implementation (wobei es hier auch noch einige
Freiheitsgrade gibt) einiges an Redundanz aufweist. Asymptotisch lässt sich der
Speicherplatz-Bedarf allerdings nicht reduzieren, da die Variante der Floyd-Wege-Matrix
oder die Floyd-Distanz-Matrix mit Θ(|V[Li]|) den Speicherplatzbedarf für ein Subnetz Li
dominiert. Daher werden wir ab jetzt diese Datenstrukturen betrachten statt eine bis ins
(nicht-asymptotische) Detail optimierte Implementation.
Nachdem wir nun wissen, wie wir die Variante der Floyd-Wege-Matrix in unsere
Datenstrukturen eingebaut haben, wollen wir im nächsten Abschnitt betrachten, was uns
dies bringt.
5.3.2 Performanz und Komplexität
Im vorherigen Abschnitt haben wir uns auf einer schon der Programmierung nahen Ebene
Datenstrukturen für die Subnetze einer Einteilung eines Straßennetzes N in Subnetze X
bei Verwendung der Variante der Floyd-Wege-Matrix überlegt. Nun wollen wir
untersuchen, was für eine Laufzeit sich damit für den Algorithmus
HIERARCHISCHE_WEGBERECHNUNG ergibt und wie der Gesamt-Speicherplatzbedarf der
Subnetze von X ausfällt.
Nach Satz 5 benötigt der Algorithmus HIERARCHISCHE_WEGBERECHNUNG O(xyz + ρ)
Zeit für die Berechnung eines kürzesten Weges, wobei
•
x = |V[L(1)] ∩ V[H]| ist,
•
y = |V[L(2)] ∩ V[H]| ist,
83
•
z = z(1) + zH + z(2) und z(1) die Dauer (obere Schranke) der Berechnung einer
kürzesten Distanz δ L(1) , zH die Dauer (obere Schranke) der Berechnung einer
kürzesten Distanz δ H , z(2) die Dauer (obere Schranke) der Berechnung einer
kürzesten Distanz δ L( 2 ) ist,
•
ρ = ρ (1) + ρ H + ρ (2) und ρ (1) die Dauer (obere Schranke) eines kürzesten Weges in
L(1), ρ H die Dauer (obere Schranke) der Berechnung eines kürzesten Weges in H,
ρ (2) die Dauer (obere Schranke) der Berechnung kürzesten Weges in L(2) ist.
Bei Verwendung der Floyd-Distanz-Matrix ist z = O(1). Da die (Variante der) FloydWege-Matrix lineare Zeit |P| für die Ausgabe eines Pfades P benötigt, beträgt die
Zeitdauer ρ für die Berechnung des kompletten Weges P bei der (Variante der) FloydWege-Matrix Θ(P). Da wir noch herausfinden müssen, ob der Zielknoten im
Stammsubnetz des Startknotens liegt, ergibt dies eine Gesamtlaufzeit von O(xy + |P| +
|V[f(i)]|).
Für Anfragen, die nicht den ganzen kürzesten Pfad erfragen, sondern nur einen Teil dieser
Information, lässt sich ρ etwas verallgemeinern. Und zwar bezeichnen wir mit ρ die
Zeitdauer der Bearbeitung einer Anfrage, die (nur) den kürzesten Weg P von i nach j
betrifft.
Bei Verwendung der normalen Floyd-Wege-Matrix, wie in Kapitel 2 definiert, beträgt die
Laufzeit ρ für die meisten1 Anfragen, die den kürzesten Weg P betreffen, Θ(P), auch wenn
sie durch weniger Informationen als durch den ganzen Weg P berechenbar sind. Dies liegt
daran, dass es mehr oder weniger „zufällig“ ist, wie P in der Floyd-Wege-Matrix
abgespeichert ist (bzw. es in der Matrix sehr viele Freiheitsgrade gibt) und man beim
Auslesen der Wurzel eines Matrix-Wegbaumes nicht viel über die beiden Unterbäume
erschließen kann.
Bei Verwendung der Variante der Floyd-Wege-Matrix dagegen gibt es schon Anfragen,
die zu dieser Matrix passen und Laufzeiten ρ von o(|P|) haben. Wenn man beispielsweise
die Straßennamen aller Straßen des kürzesten Weges P von i nach j herausfinden möchte,
dann geht das in Laufzeit ρ = Θ(Anzahl Straßenwechselpunkte von P) was gerade bei
einer hohen Granularität der Modellierung (siehe Kapitel 3) meistens deutlich kleiner sein
wird als das Durchlaufen des gesamten Matrix-Wegbaumes von P. Wie gering ρ
gegenüber |P| wird, hängt von der Art der Anfrage und dem Weg P ab und sind im WorstCase immer gleich, weil P z.B. nur aus einer Kante bestehen kann.
Wie groß kann xy sein? Im Worst-Case n2. In der Praxis, wenn man diese Algorithmen und
Datenstrukturen für wirkliche Straßennetze verwendet, ist dies wohl sehr
1 Es gibt natürlich noch Sonderfälle von Anfragen, die auch eine normale Floyd-Matrix in Zeit o(|P|) beantworten kann,
welche aber meistens vermutlich weniger praktische Relevanz haben. Ein Beispiel dafür ist die Anfrage „Enthält
der Pfad P (bzw. der kürzeste Pfad von i nach j) genau eine Kante?“. Diese Anfrage ist z.B. immer in O(1)
beantwortet, was bei Anfrage-Antwort „nein“ kleiner als |P| ist.
84
unwahrscheinlich, da man erwarten kann, dass das zugrunde liegende Straßennetz
halbwegs sinnvoll in Landkreise oder sonstige Partitionen eingeteilt ist und das
Autobahnunternetz auch sinnvoll angelegt und nicht viel zu groß ist. Ich vermute, dass xy
bei praktischen Straßennetzen deutlich kleiner als V[L(1)] und V[L(2)] ist, weil der Anteil
der Kanten (bzw. Knoten), die zum High-Level-Subnetz gehören, sehr gering ist. Wenn
dem nicht so ist, lohnt sich ein solches hierarchisches Netz weder zur Bestimmung
kürzester Wege noch als Speicherstruktur.
Für den Speicherplatz der Datenstrukturen gilt das, was wir in Abschnitt 5.2.4 bzgl. der
Güte der Heuristik festgestellt haben – allerdings im Quadrat –, denn die Variante der
Floyd-Wege-Matrix braucht (genau wie die normale Floyd-Wege-Matrix) für ein (Unter-)
Straßennetz mit n Knoten Θ(n2) Speicherplatz. Außerdem brauchen wir noch Θ(n)
Speicherplatz für die Implementierung der Funktion f mittels eines Arrays, welche hier
aber von der Größenordnung her nicht ins Gewicht fällt. Dies alles ergibt dann bei einer
Einteilung eines Straßennetzes N = (V, E, S, T, w, s, t) in Subnetze X = ({H}, {L1, L2, ...,
Lp}, f) folgenden Speicherplatzbedarf bei Verwendung der in Abschnitt 5.3.1
beschriebenen Datenstrukturen:
2
Θ(|V[H]| ) +
p
∑
Θ(|V[Li]|2)
i =1
Im Worst-Case sind |V[H]| und V[Li]| jeweils Θ(n). Dies ergibt dann folgende
Gesamtgröße der Datenstrukturen: Θ((p + 1) n2). p kann, wie wir gesehen haben, auch im
Bereich von Θ(n) liegen. Dies würde einen Worst-Case-Speicherplatzbedarf von Θ(n3)
ergeben.
Würde in praktischen Anwendungen ein Speicherplatzbedarf von Θ(n3) auftreten? Wohl
kaum. Viel eher ist folgendes Szenario möglich, dass leider, wie die meisten solcher
Überlegungen in der Diplomarbeit, nicht an praktischen Beispielen überprüft wurde,
sondern nur auf Vermutungen, ein wenig logischem Denken und Spekulationen beruht. Ab
jetzt gehen wir davon aus, dass, wie bei realen Straßennetzen, die Anzahl der Kanten m in
linearen Zusammenhang mit der Anzahl der Knoten des betrachteten Straßennetzes stehen,
also m = O(n):
Sei N1 das Straßennetz von Deutschland und es sei in Subnetze X1 eingeteilt. Das
Straßennetz N2 von Frankreich sei ebenfalls in Subnetze X2 eingeteilt. Die Low-LevelSubnetze von X1 hätten im Durchschnitt (einfach das arithmetische Mittel) die Größe d1
und die Low-Level-Subnetze von X2 die Durchschnittsgröße d2.
Angenommen, man würde nun ein konsolidiertes Straßennetz N3 erstellen, welches aus
den beiden Straßennetzen N1 und N2 besteht (und Kanten, die von N1 nach N2 gehen und
umgekehrt) und man würde es in Subnetze X3 einteilen. Für X3 kann man
höchstwahrscheinlich mehr oder weniger die alten Low-Level-Subnetze von X1 und X2
nehmen und für das High-Level-Subnetz H3 mehr oder weniger eine Vereinigung der
beiden High-Level-Subnetze H1 von X1 und H2 von X2. Damit ist die Durchschnittgröße d3
85
der Low-Level-Subnetze von H3 in etwa gleich d1 und d2. Dies ist eigentlich auch ganz
logisch, denn Straßennetze können ja (in der Praxis) nicht beliebig „dicht“ (hiermit ist
nicht die Dichtheit von Graphen gemeint) werden, sondern wachsen in erster Linie in der
Größe der bedeckten Fläche.
Das heisst, ab einer bestimmten Größe von Straßennetzen bleibt die Durchschnittgröße der
Low-Level-Subnetze einer Subnetzeinteilung in etwa konstant. Also können wir folgern,
dass demnach auch der Speicherplatzbedarf für ein einzelnes Subnetz O(1) beträgt. Der
Gesamtspeicherbedarf für die Low-Level-Subnetze beträgt dann Θ(p), wenn p die Anzahl
der Low-Level-Subnetze ist. Somit haben wir trotz Verwendung an sich quadratischer
Datenstrukturen (Variante der Floyd-Wege-Matrix) mit allen ihren Vorteilen einen nur
linearen Speicherplatzverbrauch!
Allerdings gilt dies nicht für das Autobahnsubnetz, denn dieses wächst wohl zwar von der
theoretischen Kardinalität der Knoten und Kanten genauso linear wie die Anzahl der LowLevel-Subnetze, ist aber nicht so aufgeteilt, dass wir bei quadratischen Datenstrukturen auf
einen nur linearen Speicherplatzverbrauch kommen1. Wie beim worst-case fällt auch hier
der für die Implementierung von f benötigte Speicherplatz beim Gesamtspeicherplatz nicht
ins Gewicht. Insgesamt würde dies dann einem Gesamt-Speicherplatzverbrauch von
Θ(|V[H]|2 + p)
praktische Straßennetze
=
Θ(|V[H]|2)
entsprechen. Dieses H dürfte (hoffentlich ist das Autobahnnetz gut angelegt) auch nicht
viel größer als das ursprüngliche Autobahnunternetz sein. Streng genommen ist natürlich
das Autobahnunternetz sicherlich auch linear in Anzahl der Gesamtknoten, so dass
Θ(|V[H]|2) = Θ(n2) asymptotisch gilt. Es dürfte aber für praktische Anwendungen einen
Unterschied machen, ob wir z.B. bei einem (hypothetischen) Straßennetz mit 100000
Knoten insgesamt und 10000 Knoten des Autobahnunternetzes insgesamt 1000002
Speicherplatz brauchen oder 100002.
Wenn die Low-Level-Subnetze Größe von O(1) haben, dann sind natürlich auch xy und
|V[f(i)]| in der Größenordnung von O(1), wodurch sich für die Beantwortung einer
Anfrage, welche nur einen kürzesten Weg P betrifft, sich folgende Laufzeit ergibt:
Θ (ρ)
( = O(|P|) )
1 Hier würde es sich natürlich anbieten, eine weitere Hierarchie-Ebene im Autobahn- / High-Level-Subnetz einzuführen,
sobald der Speicherplatzbedarf des High-Level-Subnetzes größer wird als der eines einzelnen Low-LevelSubnetzes.
86
5.3.3 Mögliche praktische Anwendungen
Im vorherigen Abschnitt haben wir für den worst-case und dem erhofften Fall analysiert,
wie schnell wir mit Hilfe einer Einteilung eines Straßennetzes in Subnetze, generiert durch
den Algorithmus SUBNETZ-EINTEILUNGS-GENERIERUNG, und dem Algorithmus
HIERARCHISCHE_WEGBERECHNUNG kürzeste-Weg-Anfragen beantworten können und
wieviel Speicherplatz für die Einteilung des Straßennetzes in Subnetze erforderlich ist.
Nun wollen wir uns überlegen, für was für eine Art von praktischer Anwendung dieses
Verfahren geeignet ist. Dabei betrachten wir nur den erhofften Fall einer wirklich guten
Einteilung des zugrundeliegenden Straßennetzes in Subnetze 1.
Dazu wollen wir unser hierarchisches Verfahren mit den Algorithmen von Floyd und
Dijkstra vergleichen, siehe Tab. 6:
Dijkstra
Laufzeit
O(m +
n log n
)
log log n
Speicherplatz Θ(n + m) = Θ(n)
Floyd
Unser (best-case)
Θ (|P|)
Θ(ρ)
Θ(n2)
Θ(|V[H]|2)
Tab. 6: Gegenüberstellung asymptotischer Eigenschaften von kürzeste-Weg-Algorithmen. Für
diese Laufzeiten nehmen wir m = O(n) an, wie es auch für Straßennetze aus der Realität zu
erwarten ist. Außerdem betrachten wir bei unserem hierarchischen Verfahren nur den für reale
Straßennetze erhofften und vermuteten Fall, der am Ende des vorherigen Kapitels angesprochen
wurde.
Unser hierarchisches Verfahren ist also sehr viel schneller als Dijkstra und in etwa gleich
schnell wie Floyd. An Speicherplatz verbraucht unser Verfahren asymptotisch doch noch
viel mehr als Dijkstra, weil die Komplexität des High-Level-Subnetzes sicherlich linear
abhängig von n ist. Aber der Speicherplatzverbrauch dürfte normalerweise auch noch
deutlich unter dem von Floyd liegen, trotz der Tatsache, dass vermutlich viele Knoten und
Kanten in mehr als einem Subnetz sind.
Gebrauchen kann man also dieses Verfahren für Anwendungen, für die sehr effizient
optimale kürzeste Wege berechnet werden müssen. Wenn die Wege nicht unbedingt
wirklich kürzeste Wege sein müssen, dann sind wahrscheinlich andere heuristische
Verfahren, die nur in den meisten Fällen wirklich kürzeste Wege zurückgeben, wegen
ihrem wahrscheinlich geringerem Speicherplatzverbrauch vorzuziehen.
1 Für den worst-case wird es vermutlich kaum praktische Anwendungen geben, die mit anderen Verfahren konkurieren
können. Es bleibt natürlich die Frage, ob der erwartete Fall bei Straßennetzen aus der realen Welt wirklich dieser
Best-Case ist.
87
Ein großer, bisher noch nicht angesprochener Vorteil dieses Verfahrens gegenüber von
dem von Floyd und Dijkstra ist, dass es offensichtlich sehr leicht parallelisierbar ist. Denn
man könnte jedes der p Low-Level-Subnetze einem Rechner zuordnen, ein weiterer
Rechner für das High-Level-Subnetz und dann vielleicht noch ein Anfrage-Server, an dem
man die kürzeste-Weg-Anfragen stellt und der diese dann an die entsprechenden zwei
beteiligten Low-Level-Server und dem einen High-Level-Server weiterleitet und am Ende
den konkatenierten kürzesten Weg zurückgibt. So muss auch jeder Rechner nur genug
(Haupt-)Speicher für das jeweilige Subnetz haben, das ihm zugeordnet ist.
Die Rechner für die Low-Level-Subnetze brauchen dann nur O(1) Speicherplatz, der
Rechner für das High-Level-Subnetz Θ(|V[H]|2) und der Anfrage-Server O(n) für die
Speicherung des Arrays für die Funktion f.
88
6
Implementation
In diesem Kapitel möchte ich kurz auf die in der Bearbeitungszeit der Diplomarbeit
entstandene
Java-Implementation
der
Algorithmen
SUBNETZ_EINTEILUNGS_
GENERIERUNG und HIERARCHISCHE_WEGBERECHNUNG sowie einer graphischen
Oberfläche – dem sog. Straßennetz-Editor – zum Erstellen, Editieren und Aufrufen der
beiden Algorithmen eingehen.
6.1 Bedienung und Funktionalität des Straßennetz-Editors
In diesem Abschnitt möchte ich kurz auf die Bedienung eingehen. Diese ist m.E. ziemlich
intuitiv und sollte nach 10 Minuten „rumspielen“ durchschaut sein.
Folgender Screenshot zeigt die Oberfläche des Straßennetz-Editors (siehe Abb. 26):
Abb. 26: Screenshot des Straßennetz-Editors.
Das Hauptfenster der Applikation ist in drei Teile aufgeteilt. Rechts befindet sich die
Ansicht des Straßennetzes. Links oben die Straßenliste des aktuellen Straßennetzes und
links unten die Partitionenliste (Liste der Verwaltungsbezirke). Mit der linken Maustaste
89
kann man im Straßennetz und in den beiden Listen einzelne Objekte selektieren. Mit dem
Mausrad kann man stufenlos in dem Straßennetz zoomen.
Zum Straßennetzes und dem Editor ist folgendes zu bemerken:
•
Die Knoten sind alle durchnumeriert (die Nummerierung kann aber geändert
werden).
•
Aus Zeitgründen gibt es leider nur eine Metrik und das sind Pixel bei Zoom von
100%
•
Eine Kante hat (neben Start- und Endknoten etc.) drei Attribute: Die
geometrische Länge (bzgl. der einen Metrik), Höchstgeschwindigkeit und
Fahrzeit. Relevant für kürzeste Wegberechnung ist nur die Fahrzeit. Beim
Editieren der Kanten kann man sie aber aus den anderen beiden Daten berechnen
lassen. Wenn man eine Kante erstellt, dann wird sie automatisch auf ihre
geometrische Länge bzgl. der Metrik gesetzt. Die Länge kann man natürlich
nachträglich ändern.
•
Es gibt drei Darstellungen für Kanten: Einen einfachen Pfeil, eine einfache Linie
oder einen Doppelpfeil. Erstere stellt eine gerichtete Kante dar. Die einfache
Linie stellt wie der Doppelpfeil zwei Zwillingskanten (hin und zurück vom
Startknoten) dar. Im Gegensatz zum Doppelpfeil sind bei der einfachen Linie die
3 Attribute bei den beiden Zwillingskanten gleich.
•
Es gibt drei verschiedene Ansichtsmodi: Die normale Ansicht, die SubnetzAnsicht und die Einzelschrittmodus-Ansicht. Die zweite stellt bei einer schon
berechneten Einteilung des Straßennetzes in Subnetze das aktuell selektierte (in
der Partitionenliste) in einer anderen Farbe dar. Die letzte ist die Ansicht des
Einzelschrittmodus des Algorithmus SUBNETZ_EINTEILUNGS_ GENERIERUNG.
•
Man kann neue Knoten zeichnen, indem man über das „Knoten, Kanten“-Menü
den entsprechenden Editiermodus auswählt und dann einfach auf die Karte /
Straßennetz klickt. Zum zeichnen von Kanten markiert man den Start- und
Zielknoten.
•
Mit Partitionen sind die Verwaltungsbezirke, wie z.B. Landkreise, gemeint
Nun gehen wir auf die Menüs ein:
File:
Straßennetz speichern, laden, neues erschaffen. Hierbei ist zu bemerken, dass
eine eventuell berechnete Einteilung des Straßennetzes in Subnetze nicht
gespeichert oder geladen werden kann.
View:
Hier kann man den Zoom einstellen (geht auch mit Mausrad), die Art der
Kantenbeschriftung auswählen und zwischen den Ansichtsmodi umschalten.
Edit:
Dieses Menü dient zum Löschen und Editieren selektierter Objekte.
90
Knoten, Kanten: Dieses Menü ermöglicht einem, in Editiermodi zum Einfügen von
Kanten und Knoten zu wechseln.
Strassen:
In diesem Menü kann man neue Straßen erstellen, Kanten zu Straßen
zuordnen und die Straßen automatisch für die Darstellung im Editor
färben. Diese Färbung färbt Autobahn-Kanten standardmäßig in RotTönen
und
Landstraßen-Kanten
in
Blau-Tönen.
Der
Färbungsalgorithmus sorgt dafür, dass zueinander inzidente Kanten
verschieden gefärbt sind, soweit das möglich ist.
Partitionen:
Wie das Straßenmenü, nur die Färbung färbt die Partitionen einfach der
Reihe nach.
Berechne:
In diesem Menü kann man die Algorithmen SUBNETZ_EINTEILUNGS_
GENERIERUNG und HIERARCHISCHE_WEGBERECHNUNG und den
Algorithmus von Dijkstra (zum Testen) auf das aktuelle Straßennetz
anwenden. Für die Generierung der Subnetze gibt es auch einen
Einzelschrittmodus. Hierbei ist zu bemerken, dass der Editor auf
Konsistenz zwischen dem aktuellen Straßennetz und den Subnetzen
achtet. Wenn man beispielsweise eine Einteilung in Subnetze generiert
hat und danach etwas am Straßennetz ändert, muss man die Subnetze
erst neu erstellen lassen, bevor man den Algorithmus
HIERARCHISCHE_WEGBERECHNUNG aufrufen kann (der entsprechende
Menü-Button ist dann nicht anklickbar)
6.2 Algorithmen
In diesem Abschnittt möchte ich kurz etwas zu der Implementierung der Algorithmen
SUBNETZ_EINTEILUNGS_GENERIERUNG und HIERARCHISCHE_ WEGBERECHNUNG
sagen.
Der Code ist mit dem JAVA JDK 1.4.0 b92 programmiert worden unter der
Entwicklungsumgebung von JBuilder Enterprise. Es werden Klassen aus dem JDK 1.4
verwendet (die MouseWheel Klassen), so dass das Projekt nicht unter niedriger Version
kompiliert bzw. interpretiert werden kann.
Zumindest der Code der Algorithmen SUBNETZ_EINTEILUNGS_GENERIERUNG und
HIERARCHISCHE_ WEGBERECHNUNG und der grundlegenden Straßennetz-Klassen ist
ausführlich dokumentiert.
In Abschnitt 5.3 haben wir als Datenstruktur für die Speicherung der Subnetze die
Variante der Floyd-Wege-Matrix benutzt. Diese habe ich aber am Ende aus Zeitmangel
nicht implementieren können, obwohl die Infrastruktur durch Interfaces im Prinzip schon
91
da ist. (die Algorithmen sprechen die Subnetze über Interfaces an, so dass fast beliebige
Datenstrukturen sich dahinter verbergen können). Stattdessen habe ich das Straßennetz
und die Subnetze relativ normal gespeichert mit teilweise intensiven Verpointerungen,
welche aber asymptotisch nicht ins Gewicht fallen. Kürzeste Wege ermitteln das
Straßennetz und die Subnetze mit dem Algorithmus von Dijkstra.
92
7
Zusammenfassung
Ziel dieser Arbeit ist die Entwicklung eines hierarchischen Verfahrens zur Bestimmung
kürzester Wege in einem gegebenen Straßennetz aus der realen Welt, z.B. dem
Straßennetz Deutschlands. Dieses soll vor allen Dingen sehr schnell kürzeste-WegAnfragen exakt beantworten können und der Speicherplatzverbrauch sollte unter dem von
Algorithmus Floyd bleiben.
Dazu haben wir in Kapitel 3 zuerst das theoretische Gebilde Straßennetz definiert als einen
Graphen mit ein paar zusätzlichen Funktionen, welche die Kanten zu Straßen und Straßen
zu Straßentypen, wie z.B. Autobahnen, Landstraßen, etc. zuordnen. Die Modellierung
eines Straßennetzes aus der realen Welt mit Hilfe dieser Definition ist größtenteils
straight-forward, beinhaltet aber doch ein paar Punkte, die es zu bedenken gibt und die in
Kapitel 2 angesprochen werden. Da ein solches Straßennetz in erster Linie ein Graph ist,
lassen sich die gleichen Algorithmen und (fast die gleichen) Datenstrukturen zur
Speicherung dieser verwenden. Nichtsdestotrotz besteht bei bestimmten Anwendungen
Bedarf an sehr effizienten Algorithmen zur kürzeste-Weg-Berechnung in Straßennetzen,
welche die klassische Graphentheorie nicht abdeckt.
In Kapitel 4 haben wir uns eingehend mit dem Algorithmus von Floyd beschäftigt. Dieser
gibt bekannterweise bei Eingabe eines Graphen zwei Matrizen zurück – die FloydDistanz-Matrix und die Floyd-Wege-Matrix –, welche alle kürzesten Distanzen respektive
alle kürzesten Wege des Graphen speichern. Diese beiden Matrizen kann man – nachdem
man sie ersteinmal berechnet hat – zur Beantwortung kürzester-Weg-Anfragen benutzen.
So erhält man bei Θ(n2) Speicherplatzverbrauch (n sei hierzu die Anzahl der Knoten des
Straßennetzes) in O(1) Zeit eine kürzeste Distanz und in Θ(|P|) Zeit einen kürzesten Weg
P. In der Floyd-Distanz-Matrix gibt es Freiheitsgrade der Repräsentation der in dieser
Matrix gespeicherten kürzesten Wege. Prof. Plümer hatte die Idee, diese zu benutzen, um
in der Matrix die Struktur von Wegen in Straßennetzen zu inkorporieren. Dadurch lassen
sich dann bestimmte Anfragen bzgl. kürzester Wege bei gleichem Speicherplatzverbrauch
(zumindest asymptotisch, eventuelle Verpointerungen können den tatsächlich anfallenden
Speicherplatzverbrauch ein wenig erhöhen) effizienter als in Θ(|P|) Zeit beantworten, weil
diese Anfragen nicht den ganzen Weg zurückgegeben haben wollen, sondern z.B. nur die
Straßen des Weges. Wir haben einen Algorithmus entwickelt, der eine Floyd-Wege-Matrix
innerhalb Θ(n2α) = O(n3) Zeit in die gewünschte Variante transformiert, wobei α die
durchschnittliche, ungewichtete Länge eines kürzesten Pfades in dem betrachteten
Straßennetz ist. Als Beispiel, welches auch die ursprüngliche Motivation zur Forschung im
Bereich hierarchischer Datenstrukturen war, haben wir die Variante der Floyd-WegeMatrix dazu benutzt, um das sog. Autobahnunternetz eines geg. Straßennetzes um Wege
zu ergänzen, die eigentlich schon darin enthalten sein sollten, aber nicht sind – kürzeste
Verbindungen zwischen Knoten des Autobahnunternetzes, die aber nicht im
Autobahnunternetz enthalten sind. Dies geht mit der Variante der Floyd-Wege-Matrix,
93
wenn sie schon berechnet ist, in O(n2) Zeit im Ggs. zu den normalerweise benötigten O(n3)
(zumindest für die naheliegende Implementation).
In Kapitel 5 wenden wir uns den hierarchischen Strukturen zur Speicherung von
Straßennetzen zu. Hierzu definieren wir eine sog. Einteilung eines geg. Straßennetzes in
Subnetze. Diese Einteilung enthält eine Menge von sog. Low-Level-Subnetzen und ein
High-Level-Subnetz. Jedes dieser Subnetze ist im Prinzip ein eigenes Straßennetz – ein
Teil des ursprünglichen –, welches bestimmte Eigenschaften erfüllt. Jeder Knoten des
zugrundeliegenden Straßennetzes gehört zu einem bestimmten Low-Level-Subnetz,
seinem Stamm-Subnetz. In Abschnitt 5.1.3 leiten wir einen Algorithmus her, der geg. zwei
Knoten des zugrundeliegenden Straßennetzes, die zwei Stammsubnetze der Knoten und
das High-Level-Subnetz der betrachteten Einteilung des Straßennetzes in Subnetze einen
kürzesten Weg im zugrundeliegenden Straßennetz zwischen den Knoten bestimmt. Bei
einer (gültigen) Einteilung des Straßennetzes in Subnetze gibt dieser Algorithmus immer
eine exakte Lösung aus. Dieser Algorithmus ist relativ unabhängig von den benutzten
Datenstrukturen zur Speicherung der Subnetze definiert. Die Laufzeit ist demnach von den
bentzten Datenstrukturen abhängig und wie das Straßennetz in Subnetze eingeteilt wurde.
Im Abschnitt 5.2 überlegen wir uns, wie wir aus einem Straßennetz die bisher nur
theoretisch definierte Einteilung in Subnetze erhalten können und welche zusätzlichen
Eigenschaften diese erfüllen sollten, um den Speicherplatzverbrauch zur Speicherung
dieser und die Laufzeit für den Algorithmus aus Abschnitt 5.1.3 niedrig zu halten. Dies
überlegen wir uns auch ohne Betrachtung der konkreten Datenstrukturen zur Speicherung
der (theoretisch definierten) Subnetze. In Abschnitt 5.2.3 leiten wir eine Heuristik her, die
aus einem gegebenen Straßennetz, einer Partitionierung dessen in Verwaltungsbezirke
(z.B. Landkreise) und dem Autobahn(unter)netz des Straßennetzes eine Einteilung in
Subnetze generiert. Die Heuristik besteht darin, dass die zuvor überlegten
wünschenswerten Eigenschaften / Optimierungskriterien, nicht unbedingt erfüllt sind. Die
Laufzeit beträgt Θ(n3) und der Speicherplatzbedarf entspricht dem von dem
zugrundeliegenden Straßennetz und der kompletten generierten Einteilung in Subnetze. Es
zeigt sich, dass die Heuristik zumindest in konstruierten Beispielen sehr große
(quadratisch in Anzahl der Kanten und Knoten des eingegebenen Straßennetzes),
ungünstige Einteilungen des Straßennetzes in Subnetze generieren kann. In der Praxis ist
dies wahrscheinlich nicht zu erwarten. Da vermuten wir eher den Best-Case. In dieser
Diplomarbeit gibt es aber diesbezüglich keine empirischen Untersuchungen.
Im Abschnitt 5.3 betrachten wir erstmals eine konkrete Datenstruktur zur Speicherung der
Subnetze – die Variante der Floyd-Wege-Matrix. Diese braucht zwar normalerweise in
Anzahl der Knoten quadratischen Speicherplatz, aber es ist zu erhoffen, dass die Heuristik
das zugrundeliegende Straßennetz gut in einzelne kleinere Teile – die Subnetze – zerlegt
hat und demnach der Speicherplatzbedarf deutlich niedriger als normalerweise ist (sowohl
insgesamt wegen dem Quadrat als auch der Tatsache, dass man für eine kürzeste-WegBerechnung nur drei Subnetze von möglicherweise sehr vielen braucht und die
Berechnung verteilt bearbeiten kann). In Abschnitt 5.3.2 argumentieren wir (wobei ich den
letztendlichen theoretischen oder empirischen Beweis schuldig bleibe), dass wir ein reales
94
Straßennetz (mit Hilfe des einen Algorithmus) dann so in Subnetze zerlegen können, dass
diese Einteilung in Subnetze insgesamt Θ(|V[H]|2) Speicherplatz benötigt, wobei V[H] in
etwa der Größe des Autobahnunternetzes entspricht, und mit ihr in Θ(ρ) = O(|P|) Zeit
kürzeste-Wege-Anfragen beantworten können. Hierbei gilt Θ(ρ) = o(|P|) für spezielle
Arten von Anfragen bzgl. kürzester Wege, für welche die Variante der Floyd-WegeMatrix gut geeignet ist.
In Kapitel 6 wird kurz auf eine im Verlauf der Bearbeitungszeit entstandene
Implementation der in dieser Diplomarbeit entwickelten Algorithmen eingegangen. Diese
besteht aus einem Editor zum erstellen, editieren, speichern und laden von Straßennetzen
und der Möglichkeit zum Aufruf der Implementationen zur hierarchischen Ermittlung
kürzester Wege. Als Datenstruktur wurde hier aus Zeitmangel noch nicht die (Variante
der) Floyd-Wege-Matrix benutzt.
Nun möchte ich einen kleinen Ausblick über weiterführenden Forschungsbedarf in dieser
Thematik geben. Zum einen sind unbedingt Untersuchungen der Performanz und des
Speicherplatzverbrauchs des in dieser Diplomarbeit hergeleiteten Verfahrens für aus der
Realität stammende Straßennetze erforderlich, da dieses Verfahren eben eine Heuristik
bzgl. dieser beiden Dimensionen ist. Dazu ist höchstwahrscheinlich auch eine
Implementation zu programmieren bzw. die während dieser Diplomarbeit entstandene
entsprechend zu erweitern, die als Datenstrukturen – wie in dieser Diplomarbeit
theoretisch auch behandelt, aber praktisch aufgrund von Zeitmangel nicht umgesetzt – die
Variante der Floyd-Wege-Matrix benutzt.
Wenn sich dieses Verfahren durch Tests für die Praxis als tauglich erweist, wäre eine
eingehendere Untersuchung der worst-, average- und best-cases sowie
Wahrscheinlichkeitsverteilungen bzgl. realer Straßennetze wünschenswert. Dazu müssten
wahrscheinlich reale Straßennetze in theoretischer Hinsicht genau untersucht und
klassifiziert werden, um solche theoretischen Resultate gewinnen zu können.
Umso besser wäre natürlich ein Algorithmus, der die hierarchischen Datenstrukturen bzgl.
bestimmter, sinnvoller Kriterien immer optimal generiert, falls dies möglich ist. Es ist aber
nicht auszuschließen, dass manche dieser (Optimierungs-)Probleme NP-hart sind.
Weiterhin besteht eventuell Forschungsbedarf, dieses Verfahren für mehr als nur zwei
hierarchische Ebenen weiterzuentwickeln, falls durch Tests nachgewiesen wurde, dass es
so schon zumindest einigermaßen tauglich für die Praxis ist.
Zuletzt könnte die Suche nach weiteren Anwendungen für die Variante der Floyd-WegeMatrix gewinnbringend sein. Vielleicht gibt es ein (möglichst praktisch relevantes)
Problem, welches durch die Anwendung der Matrix inklusive der O(n3) Zeit für die
Berechnung der Matrix schneller lösbar ist als ohne.
95
Literatur
[BLUM98] Blum, N. (1998): Theoretische Informatik : Eine anwendungsorientierte Einführung.
R. Oldenbourg Verlag München Wien 1998. 1. Auflage
{BRAN94] Brandstädt, A. (1994): Graphen und Algorithmen. B.G. Teubner Stuttgart 1994
[HASS00] Hasselberg, S. (2000): Some results on heuristical algorithms for shortest path
problems in large road networks, Inaugural-Dissertation zur Erlangung des Doktorgrades
der Mathematisch-Naturwissenschaftlichen Fakultät der Universität zu Köln, Köln 2000
[KRUM00] Krumke, S.O., Noltemeier, H. et al. Graphentheoretische Konzepte und Algorithmen.
Vorlesung Universität Würzburg. Würzburg 2000. URL: http://www-info1.informatik.uniwuerzburg.de/vorlesungen/SS99/graphentheorie/vorlesung.pdf
[LEDA99] Mehlhorn, K., Näher, S. (1999): LEDA :A platform for combinatorial and geometric
computing. Cambridge University Press, Cambridge 1999
96
Erklärung
Hiermit erkläre ich, dass ich die vorliegende Arbeit selbstständig verfasst und keine
anderen als die angegebenen Hilfsmittel benutzt habe. Die Arbeit wurde bisher keiner
anderen Prüfungsbehörde vorgelegt und auch nicht veröffentlicht.
Bad Honnef, den 10.07.2002
______________________________________
( Lasse Asbach)
97
Herunterladen