cards-deck: 100-199_university::111-120_theoretic_cs::111_algorithms_datastructures

| MST | M inimal S panning T rees

anchored to [[111.00_anchor]] proceeds from [[111.13_Graphen_basics]] and [[111.23_Graphen_ZHK]]


| Overview |

| Intuition |

Wir möchten das Prinzip eines MST durch ein Beispiel näher bringen. Betrachten wir ein Netz von Computern. Wir möchten jetzt ein Netzwerk bauen, bei welchem alle Computer verbunden sind, und dabei die Kosten gering bleiben. Also wir wollen einen Teilgraph des Gegebenen betrachten, sodass wir darin dann die minimalste Verbindung finden können

[!Example] Beispiel MST ( rot ) in einem Graphen ![[Pasted image 20221121141641.png]] Zu erkennen sind hier folgende Eigenschaften des Baumes:

  • erst ist azyklisch ( also wir haben keine Zykel in der Verbindung) [[111.18_Graphen_Traversieren]]
  • ist der günstigste Weg, der in diesem Graph möglich ist \

[!Important] ein MST ist immer ein [[111.08_algo_datastructures#Trees Grundlegende Definition|Tree]] warum ist das so? #card Wenn man die Knoten, die durch einen MST genommen werden, betrachtet, dann wird man hier immer einen BAUM erhalten. -> Dabei hat jeder Knoten viele Leafs, die dann wieder welche haben können Aber es kann hier keine Zykel geben, also wird dieser Baum nur in die Tiefe ausgebaut, aber nicht mehr nach oben verlinken. ( Es ist einfach eine Baum-Struktur D: ) ^1704708900392

| Historische Betrachtung von MST |

Für eine historische Betrachtung der Konzeptionen zur Findung von MST können wir folgend betrachten:

  1. Kruskal’s algorithm -> published in 1956
  2. Union-Find data structure (by Fisch, Galler) -> published in 1964
    • there are still improvements and publication happening for this structure now!
  3. Prim’s algorithm ->published 1957
    • R. Prim - shortest connection networks and some generalizations.
    • ((maybe already invented by V. Jarnik 1930))

| Definition | MST |

Wir wollen ferner noch definieren, was einen MST ausmacht.

[!Definition] Definition MST was ist ein MST von einem Graphen ? 3 Eigenschaften #card Sei ein ungerichteter Graph mit Knoten und Kanten. Wir benennen jetzt einen Teilgraph mit $V’ \subset V, E’ \subsetE$ als aufspannenden Baum, wenn folgendes für gilt: 1. T ist azyklisch (acyclic)

2. , also der Teilgraph beinhaltet alle Knoten aus dem originalen Graph

3. , also die Menge der Kanten ist minimal und damit eigentlich 1 kleiner, als die Menge der Knoten ^1704708900404

[!Important] Kosten beim MST wie sind die Kosten des Teilbaumes /Graphen definiert? #card Betrachten wir den entstehenden Teilgraphen , dann werden dessen Kosten folgend definiert: Also die Kosten aller Kanten werden einfach summiert.

Wichtig ist, dass die Kosten hier minimal sein müssen! ^1704708900412

Betrachten wir dafür noch ein Beispiel, damit die Intuition innerhalb eines Graphen etabliert und verstanden werden kann.


| Nicht-Eindeutigkeit |

Sofern bei einem Graphen mehrere kürzeste Pfade zu bestimmten Knoten existieren, können diese mehreren Pfade auch angewandt werden, um etwa einen MST verschieden aufzuspannen.

[!Definition] MST sind nicht zwingend eindeutig warum? #card Sofern unser Graph mehrere kürzeste Pfade zu bestimmten Punkten hat, kann ein MST auch aus diesen einzelnen Pfaden aufgebaut werden.

Somit gibt es dann mehrere MST für einen Graphen –> Sie sind also nicht zwingend eindeutig in ihrer Definition ! ^1704708900421


| Beispiele für MST |

| Beispiel 1

[!Example] Graph und dessen MST ![[Pasted image 20231208200034.png]] Wie könnte in diesem Graph ein MST aussehen? #card ![[Pasted image 20231208200104.png]] -> Dieser Graph ist Zykelfrei! er hat die kürzesten Pfaden drin ^1704708900429

| Beispiel 2

Wir können noch ein Beispiel betrachten:

[!Example] ![[Pasted image 20221121151340.png]] ![[Pasted image 20221121151346.png]] ![[Pasted image 20221121151355.png]]


| MST | Bestimmen / Finden |

Wir möchten jetzt verschiedene Wege finden, um einen MST bestimmen und aufbauen zu können.

| Kruskal’s Algorithmus | Greedy | #refactor

Wir möchten dafür zuerst einen [[111.39_greedyAlgorithm|Greedy Algorithmus]] betrachten, welcher Schritt für Schritt die beste Option für einen MST sammeln wird.

[!Definition] Kruskal’s Algorithmus wie funktioniert dieser, was macht er? #card

\begin{algorithm} 
  \caption{Kruskal's Algorithmus} 	
	\begin{algorithmic} 
	\State $\text{sort edges in nondecreasing order by weight w} e_1,\dots,e_m \text{ so dass} c(e_1) \leq c(e_2) \leq \dots \leq c(e_m)$
	\State initialize  $E_{T} = \emptyset$ 
	\For{$i = 1, \dots,m$} 
	\Comment{traverse all edges from graph}
		\If{$E_{T} \cup \{ e_{i} \} acyclic$}
			\State $E_{T} = E_{T} \cup \{ e_{i} \}$ 
			\Comment{also immer die nächst kleinere Kante übernehmen, und schauen, dass es azyklisch bleibt}
		\EndIf
	\EndFor
	\end{algorithmic} 
\end{algorithm}

Intuition: Der Algorithmus sucht also von der geringsten zur höchsten Wichtung der Kanten, immer die heraus, sodass folgende Eigenschaften erhalten werden:

  • der Graph bleibt azyklisch ( wir schauen also, dass der entstehende Graph sich nicht looped)
  • der Graph bleibt minimal ^1704708900437

Intuition von Kruskal’s Algorithmus :

  • Wir fangen also mit einem leeren Baum an, den wir jetzt immer mit der günstigsten Kante füllen wollen
    • wir fügen jetzt immer die günstigste Kanten zum Baum hinzu und schauen, dass kein Zykel entsteht
  • Wenn alle Knoten erreicht werden beenden wir den Algorithmus

[!Error] Kruskal ist ein dezentraler Algorithmus, also er sucht global eine Lösung und fügt sie anschließend zusammen

[!Important] Korrektheit von Kruskal’s Algorithmus | warum ist dieser Algo korrekt? #card Mit jeder Iteration, suchen wir von den geringsten Kanten ( deren Gewichten ) diese, die man in den neuen Graphen ( dem MST) aufnehmen kann, ohne dabei ein Zykel zu erzeugen. Das heißt also: Jede minimale Verbindung zwischen zwei Knoten wird betrachtet und anschließend übernommen. Wenn sie dann ein Zykel bildet, heißt das, dass wir in einer vorherigen Iteration ( wo die Gewichte kleiner waren!) schon eine Verbindung dahin gefunden haben, also schon die geringste Verbindung besteht!

Dadurch wird der Algorithmus mit jeder Iteration diese Eigenschaft des minimalsten Spannbaumes erhalten! ^1704708900447


Wir möchten bei dem Beweis der Korrektheit des Algorithmus einer bestimmten Intuition folgen:

–> Bedeutung “gut”: eine Menge nennen wir jetzt gut, wenn sie zu einem MST erweitert werden kann ( also minimal ist und azyklisch ist!)

| Nitpick | Finden von guten Kanten |

Wir können bestimmte Paradigmen betrachten, um solche guten Kanten in einem Graphen finden zu können. Mehr dazu findet sich hier [[111.29_Graphen_MST_find_safe_edges]]

| Beweis der Korrektheit |

[!Important] Ansatz des Korrektheitsbeweises Sei eine gute Teilmenge und sei hier die billigste Kante, so adss azyklisch ist (bleibt). Aus dieser Betrachtung folgt jetzt, dass weiterhin gut ist

Mit dieser Annahme können wir jetzt folgend die Korrektheit beweisen:

Sei jetzt die Erweiterung von zu einem MST.

  1. Ist jetzt , so ist auch gut -> also stimmt unsere Behauptung
  2. Ist jetzt dann betrachten wir
    • in dieser Betrachtung enthält dann H einen Zykel –> denn ist schon ein MST, brauch aber scheinbar nicht -> also wird er schon von einer anderen Kante abgedeckt
    • Da auch azyklisch ist, gibt es in dem Zykel eine Kante , die nicht in liegt Da wir entsprechend gewählt haben: ( weil wir ja von geringer, nach höherer Wichtung sortiert haben!) -> Da ein MST ist, so erhalten wir auch einen MST, wenn durch ersetzt wird ( da die beiden Eigenschaften erhalten werden!)

Beispiel Anwendung | Kruskal |

Betrachten wir folgenden Graphen, dann möchten wir hier als Beispiel Kruskals-Algorithmus zum bestimmen eines MST anwenden:

[!Example] Betrachte folgenden Graphen: ![[Pasted image 20221121142820.png]] Unter Anwendung von Kruskal: wie könnte ein möglicher MST aussehen? #card Wir würden chronologisch die kleinsten Kanten nacheinander betrachten und dann einen MST bauen können: mögliche Konstruktion:

  1. B–>C
  2. C–>D
  3. C–>F
  4. F–>E
  5. D–>A ^1704708900457

| Kruskal | Implementieren |

Vorbetrachtung: Wenn wir den Algorithmus tatsächlich implementieren wollen, müssen wir bestimmte Dinge beachten und prüfen:

  • Testen, ob eine neue potentielle Kante ein Zykel erzeugen würde, oder nicht
  • wir müssen die Kanten nach Gewicht ordnen

[!Definition] Ein möglicher Ansatz zum Verhindern von Zykeln Wir könnten uns Partitionen der Knoten erzeugen, sodass die Kanten aus (also dem zu erzeugenden Baum) immer auf die Knotenmenge induzieren. Durch diese Betrachtung: Hängen dann für die Teilmengen nicht zusammen Wir können so also zum Anfang eine eine Partitionierung, folgend aufbauen: –> also für jeden Knoten ein eigenes Set ( eigene Partition aufmachen).

| Kruskal’s Algorithmus | UNION <> FIND |

Durch diesen Ansatz Zykel zu verhindern müssen wir jetzt folgend zwei Operationen definieren:

  1. Find(x) –> liefert den Namen der Menge ( Partition) , wo der gesuchte Knoten drin ist –> damit wir wissen, ob er sich in einer Partition befindet, die wir schon haben / oder nicht
  2. Union(A,B) –> Wir vereinigen zwei Mengen (Partitionen) und zu einer einzigen!
    • damit werden dessen Inhalte also zusammengefasst ( und wir wissen, dass da kein Zykel ist!)

[!Important] Intuition dieser Implementierung wenn wir Find und Union einbringen und alles in Partitionen aufteilen, was ist es dann für ein Algorithmus? #card Wir haben hier mehr oder weniger Union-Find aufgebaut, wo wir quasi Schritt für Schritt kleine “Blasen” von Knoten nacheinander verbinden und zu einer großen Zusammenführen.

Dadurch haben wir am Ende eine Implementation, die folgend den MST aufgebaut hat! ^1704708900465

Ferner wollen wir die Erweiterung zu Union-Find betrachten wie funktioniert dieser ALgorithmus? #card

\begin{algorithm} 
	\caption{erweiterer Kruskal Algorithmus}
	\begin{algorithmic} 
	\State $\text{sort edges in nondecreasing order by weight w} e_1,\dots,e_m \text{ so dass} c(e_1) \leq c(e_2) \leq \dots \leq c(e_m)$
 		\State initialize  $E_{T} = \emptyset$ 
 		\Comment{der Anfang ist also gleich, wie vorher!}
 		\For{$i = 1,\dots, m$}
	 		\State sei $e_{1}= (v,w)$
	 		\Comment{also wir schauen, uns die Verbindenden Knoten der Kante e an!}
	 		\State $A = Find(v)$
	 		\State  $B = Find(w)$ 
	 		\If{($A \neq B$)}
		 		\State $E_{T}= E_{T} \cup \{ e_{i} \}$
		 		\State $Union(A,B)$
		 		\Comment{Wir haben zwei unverbundene Partitionen gefunden, also kein Zykel, wenn wir sie verbinden!}
	 		\EndIf
 		\EndFor
	\end{algorithmic}
	\end{algorithm}

Wir wollen hier noch betrachten, wie dann die Funktionen Find und Union aussehen müssen: Dafür müssen wir uns folgende Struktur für eine solche Partition überlegen: ^1704708900474

[!Definition] Forderung für die Abbildung wie sehen die Funktionen Find / Union für Union-Find aus? Was brauchen sie? #card , so dass Also sie muss bei einem gegebenen Knoten sagen können, wo dieser drin ist.

Daraus können wir jetzt Union und Find ableiten und definieren:

\begin{algorithm} 
\caption{Find(x)} 
  \begin{algorithmic} 
  	\Return $R(x)$ 
  	\Comment{find(x) gibt also einfach den Wert, der sich in R befindet }  
  	\end{algorithmic} 
\end{algorithm} 

und weiter noch

\begin{algorithm}
\caption{Union(A,B)}
\begin{algorithmic} 
\For{$i = to~ n$} 
\If{$R(i) = A$}
\State $R(i) = B$
\Comment{Wenn der Knoten i in A ist, dann setzen wir ihn auf B}
\EndIf 
\EndFor 
\end{algorithmic}
\end{algorithm} 

^1704708900483

| Laufzeit 2. Kruskal’s Algorithmus |

Wir möchten jetzt für die erweiterte Struktur die Laufzeit betrachten und evaluieren:

[!Tip] Laufzeit-Betrachtung mit Erweiterung durch Find / Union wie ist die Laufzeit beider Implementationen? #card Wir wissen:

  • dass ist, da es nur einen Wert ausgeben muss, der sofort abrufbar ist
  • dass -> da es jeden einzelnen Knoten durchgeht und zu B hinzufügt, wenn er in A ist ! Weiterhin schauen wir jetzt, wie oft wir diese beiden FUnktionen ausführen:
  • -> weil wir alle Kanten betrachten
  • -> weil wir nach und nach von N viele Partitionen in eine einzige Reduzieren werden!

Dadurch resultiert folgende Laufzeit: ^1704708900493

Ein Problem was hier auftritt: Union ist zu langsam mit ! -> Um das zu lösen könnte man beispielsweise die Namesänderung proportional zur Größe der kleineren Menge machen und somit den Namen der größeren beibehalten ( dadurch müssen wir nicht alles traversieren)


| Verbessern von |

Aus der Betrachtung heraus, dass unser angepasster Kruskal-Algorithmus aufgrund der Union-Funktion relativ langsam werden kann, möchten wir eine bessere Implementation betrachten, den den obigen Vorschlag einbezieht, dass man die Namensänderung proportional zur Größe der kleineren Menge umsetzt.

[!Definition] Anpassung von für eine schnellere Union/Find Implementation was müssen wir jetzt für die Partitionen weiter betrachten, um sie schneller zu bekommen? #card Für die neue Implementation brauchen wir folgende Grundstrukturen:

  1. die Mengen ( Partitionen) sollen jetzt Listen sein. Ihre Größe muss gemerkt werden (damit wir sie später vergleichen können!)
  • die Größe soll mit abgerufen werden können!
  1. die Abbildung soll weiterhin erhalten bleiben, also für ! ^1704708900501

[!Important] Es müssen jetzt folgende Anpassungen für den PseudoCode von Kruskal eingebracht / umgesetzt werden: welche 2 sind es? #card

  1. initialisieren der Größe jeder Partition am Anfang des Algorithmus!
  2. die Union-Funktion muss angepasst werden, sodass sie nach der Größe entsprechend zusammenfässt
  3. bleibt gleicht ^1704708900514

| Aktualisierter PseudoCode | Was müssen wir mit unserer neuen Implementation ändern? Wie sieht jetzt aus? #card

\begin{algorithm} 
	\caption{erweiterter Union / Find Algorithmus }
	\begin{algorithmic} 
		\Procedure{initializePartition}{}
			\For{$i = 1,\dots,n$}
				\State $R(i) = i$ 
				\State $Elem(i) = i$
				\State $size(i) = 1$
				\Comment{Wir initialisieren hier die Partitionen und setzen ihre Größe auf 1} 
			\EndFor 
		\EndProcedure
	
		\Procedure{find}{x}
			\Return $R(x)$
		\EndProcedure
		
		\Procedure{Union}{A,B}
			\If{$size(A) < size(B)$} 
				\State tausche A und B 
			\EndIf 
			\For{all $x \in Elem(B$}
				\State $R(x) = A$
				\State append(x,Elem(A)) 
				\Comment{we are now expanding A with all entries of B}
				\Comment{For that reason we are also swapping A and B, in case B is larger; we always append the smaller partition to the larger one} 
			\EndFor
		\EndProcedure
	\end{algorithmic} 
	
\end{algorithm} 

^1704708900523

| Laufzeit von |

Wir haben durch diese Anpassung jetzt eine neue Laufzeit für Union etablieren können.

[!Definition] Laufzeit vom neuen warum ist es jetzt schneller, was ist besser? #card Da wir jetzt bei Union nicht mehr alles durchlaufen, sondern nur die Elemente der kleineren Menge, können wir entsprechend reduzieren, wie viele Knoten wir per Durchlauf anschauen müssen!

Es folgt eine neue Laufzeit: ^1704708900530

| Verbesserte Laufzeit von Kruskal’s Algorithmus mit neuem |

Da wir jetzt die Laufzeit reduzieren bzw von den Größen der Partitionen abhängig machen, können wir in der allgemeinem Implementation [[#Kruskal’s Algorithmus UNION <> FIND]] eine neue Laufzeit betrachten.

[!Tip] Laufzeit des Algorithmus ( Unions werden ausgeführt) inwiefern ist jetzt die Laufzeit anders, wenn wir den neuen Union-Algo nutzen? #card Die insgesamt Unions, die wir im Algorithmus ausführen, haben jetzt folgende Laufzeit: wobei hier die Größe der kleineren Partition ist, bei der -ten Iteration des Algorithmuses ( das kommt daher, dass wir ja immer nur die kleinere Menge in den großen einfügen müssen, und somit nur diese Einträge durchlaufen und aktualisiert werden müssen!)

Es gilt jetzt folgend: wobei jetzt die Zahl der Mengenwechsel für angibt. ^1704708900539

Wir können daraus folgende Behauptung entnehmen / betrachten: Behauptung: für a ( also jedes Element wird ) mal seine Menge (Partition) wechseln wie können wir das beweisen? #card Beweis: Wenn die Partition wechselt, und vorher in einer Menge mit Einträgen ( Knoten) war, dann die neue Menge die Größe . Gleichzeit haben wir nach wechseln dann eine Größe von aufgebaut und daraus folgt jetzt: –> Es folgt also daraus, dass wir immer größere Mengen erhalten und die kleinen Partitionen in die größeren fallen, dann der Fall, dass jeder Eintrag mal die Partition / Menge wechseln wird / kann! ^1704708900547

[!Definition] aktualisierte Laufzeit von Kruskal’s Algorithmus | Union Find Es resultiert eine Laufzeit

( es ist hier die amortisiert Analyse von Union-Find)

| Prim’s Algorithmus | Dijkstra aber für MST |

Neben Kruskal können wir jetzt noch eine Implementation betrachten, welche in ihrem Prinzip [[111.22_Graphen_SSSP_dijkstra]] ähnelt.

-> [[111.27_Graphen_MST_Prims_Algorithm]]