Dieser Teil ist sehr technisch und wahrscheinlich vorerst nicht Teil der Vorlesung.
Traditioneller paralleler Mergesort
In den vorherigen Kapiteln haben wir Mergesort "wie üblich" durchgeführt und uns darauf konzentriert, eine möglichst effiziente parallele Variante von Merge zu entwerfen. Die Makrostruktur des Algorithmus sah dann - unabhängig von dem Merge-Algorithmus - in etwas so aus:
In jedem Schritt $t$ verteilen sich die $n$ Prozessoren auf die $2^{\log(n)-t}$ Knoten auf Ebene $t$ (Ebene $0$ sind die Blätter), um pro Knoten die zwei von unten kommenden sortierten Listen zu mittels Merge zu einer sortierten List der Länge $2^t$ zu verschmelzen.
Versetzen Sie sich in die Lage eines Knotens auf Ebene $t$. Sie haben in Schritt $t$ eine Menge von $2^t$ Prozessoren zur Verfügung. Um auf eine Gesamtlaufzeit von $O(\log n)$ zu kommen, müsste der Merge-Schritt in $O(1)$ Zeit ablaufen. Dies ist leider nicht möglich.
Vorkenntnisse. Für einen Knoten $u$ in dem Binärbaum sei $L_u$ die sortierte Liste aller Elemente, die an den Blättern im Teilbaum von $u$ stehen. Für das linkeste Blatt auf Ebene 2 im obigen Beispiel wäre dies [be, it, to, up]. Ziel ist es, $L_{\rm root}$ zu berechnen. Sei $u$ ein Knoten und seien $v$ und $w$ seine Kinder. Coles zentrale Entdeckung ist, dass man zwei Listen $A$ und $B$ dann in $O(1)$ verschmelzen kann, wenn man schon eine grobe Vorstellung hat, wie $A$ und $B$ aussehen. Zum Beispiel wenn man als "Skizze" eine Liste $U$ hat und (1) jedes Element in $U$ seinen Rang in $A$ und in $B$ kennt und (2) die Intervalle, in die $A$ und $B$ durch die Elemente aus $U$ geteilt wird, nur konstante Größe haben. Wir haben nun mehrere Herausforderungen.
- Statt wie im obigen Beispiel einfach alle Elemente von Knoten $v$ zum Elternknoten $u$ zu schicken, müssen wir festlegen, wie Knoten $v$ eine Skizze seiner derzeitigen Liste nach $u$. Jeder Knoten $u$ hat also "vorläufige" Liste $L(u,t)$ zum Zeitpunkt $t$ (die hoffentlich irgendwann wirklich zu $L_u$ wird).
- Wir müssen die Bedingung (2), also die Teilintervalle haben konstante Größe sehr sorgfältig formulieren, damit wir es als Schleifeninvariante tatsächlich beweisen können.
- Wir müssen zeigen, welche Zusatzinformation wir brauchen, damit wir alles Merge-Operationen wirklich in konstanter Zeit erledigen können.
Stichproben weiterschicken
Jeder Knoten $v$ enthält zum Zeitpunkt $t$ eine sortierte Liste $L(v,t)$ aus Elementen. Für einen inneren Knoten $v$ ist $L(v,0) = [\ ]$. Für ein Blatt $v$ ist $L(v,0)=[x]$, enthält also genau ein Element aus unserer zu sortierenden Eingabeliste. So weit alles so wie beim "traditionellen" parallelen Mergesort oben. Wir werden nun eine Choreographie entwickeln, nach der Knoten $v$ auf bestimmten Ebenen Stichproben $S(v,t)$ ihrer derzeitigen Liste $L(v,t)$ nach "oben" zu ihrem jeweiligen Elternknoten $u$ schicken. Wenn also $u$ die Kinder $v$ und $w$ hat, dann gilt
\begin{align*} L(u, t+1) = \texttt{merge} (S(v,t) \cup S(w,t) ) \end{align*}Beispiel. Wir beschreiben eine Choreographie, nach der ein Knoten $v$ bestimmt, welche Elemente er zum Zeitpunkt $t$ zu seinem Elternknoten weiterschickt.
- Schicke jedes zweite Element nach oben (angefangen bei Element 1). Wenn also $L(u,t) = [x_1, x_2, \dots, x_m]$ ist, dann ist $S(u,t) = [x_1, x_3, x_5, \dots]$.
Diese Choreographie führt natürlich nie zum Ziel, da zum Beispiel das Element mit Rang 2 nie über Level 1 hinauskommt (und es überhaupt nur das Minimum bis ganz oben schafft). Wir brauchen also eine Choreographie, in der ab irgendeinem Zeitpunkt ein Knoten seine Gesamtliste nach oben weiterleitet.
Beispiel. Wir beschreiben hier eine zweite Choreographie.
- Wenn $t \geq 2$ und $L(u,t-1) = L(u)$ ist, schicke die Gesamtliste weiter: $S(u,t) := L(u,t)$.
- Ansonsten schicke jedes zweite Element von $L(u,t)$ weiter, angefangen beim ersten; formal $S(u,t) := [x \in L(u,t) \ | \ \rank(x, L(u,t)) \textnormal{ ist ungerade}]$.
Die Bedingung $L(u,t-1) = L(u)$, dass also die Liste schon vor zwei Schritten vollständig geworden ist, stellen wir graphisch durch Punkte versus Kreuzchen dar: anfangs symbolisieren wir Elemente durch Punkte; wenn zum ersten Mal $L(u,t) = L(u)$ gilt, so werden sie ab Schritt $t+1$ durch Kreuze dargestellt; wenn $L(v,t)$ aus Kreuzen besteht, schicken wir sie vollständig in Schritt $t+1$ nach oben weiter.
Die Entwicklung von $|L(u,t)|$ in Abhängigkeit vom Level $i$ des Knotens $u$ und des Zeitschrittes $t$ können wir schön in einer Tabelle darstellen.
Übungsaufgabe Betrachten Sie die folgende Choreographie:
- Wenn $L(u,t-1) \ne [\ ]$, dann setze $S(u,t) = L(u,t)$, schicke also alle Elemente weiter.
- Wenn $L(u,t-1) = [\ ]$, dann schicke jedes zweite Element weiter.
Jeder Knoten schickt also nur einmal eine nichtleere, aber auch nicht vollständige Stichprobe nach oben weiter. Die zweite Stichprobe ist dann schon die Gesamtliste, der er im Moment hat. Erkunden Sie die Dynamik dieser Choreographie und erstellen Sie eine Tabelle noch obigen Beispiel.
Die Dynamik in unserem zweiten Beispiel (wo wir jedes zweite Element weiterschicken bis $L(u,t-1) = L(u)$ vollständig geworden ist) schaut recht freundlich aus; leider werden wir weiter unten feststellen, dass sie aus anderen Gründen nicht zu verwenden ist. Wir betrachten daher eine weitere Choreographie, für die der Algorithmus dann funktionieren wird.
Übungsaufgabe Betrachte folgende Dynamik:
- Wenn $t \geq 2$ und $L(u,t-1) = L(u)$ ist, schicke die Gesamtliste weiter: $S(u,t) := L(u,t)$.
- Ansonsten schicke jedes vierte Element von $L(u,t)$ weiter, angefangen beim ersten; formal $S(u,t) := [x \in L(u,t) \ | \ \rank(x, L(u,t)) \textnormal{ ist ungerade}]$.
Untersuchen Sie die Dynamik dieser Choreographie, indem Sie eine Tabelle nach obigem Beispiel zeichnen.
Grobstruktur des Algorithmus
Wir nehmen an, dass die Länge $n$ der Eingabeliste $[x_1,x_2,\dots,x_n]$ eine Zweiterpotenz ist $n=2^d$. Wir betrachten einen Binärbaum der Höhe $d$. Der $i$-te Level des Baumes besteht aus den Knoten mit Abstand $d-i$ zur Wurzel; Level $0$ sind also die Blätter. Jedes Blatt trägt als Label ein Element der Inputliste. Für einen Knoten $u$ bezeichne $L(u)$ die Liste der Labels der Blätter seines Unterbaumes in sortierter Reihenfolge. Falls $u$ auf Level $i$ ist, so gilt also $|L(u)| = 2^i$; insbesondere ist $L(\root)$ die sortierte Eingabeliste, also das gewünschte Ergebnis. Jeder Knoten $u$ des Baumes unterhält zum Zeitpunkt $t$ eine sortierte Liste $L(u,t)$. Anfangs setzen wir
\begin{align*} L(u,0) := \begin{cases} x_i & \textnormal{ falls $u$ das $i$-te Blatt des Baumes ist} \\ [\ ] & \textnormal{ falls $u$ kein Blatt ist. } \end{cases} \end{align*}Für eine Liste $L$ sei $\samplekth(L)$ die Liste bestehend aus jedem $k$-ten Element, angefangen beim ersten. Formal
\begin{align*} \samplekth(L) := \{x \in L \ | \ \rank(x,L) \equiv 1 \mod k\} \end{align*}So ist zum Beispiel
\begin{align*} \sample_3([\texttt{am}, \texttt{be}, \texttt{he}, \texttt{in}, \texttt{on}, \texttt{to}, \texttt{us}]) = [\texttt{am}, \texttt{in}, \texttt{us}] \end{align*}Weiterhin definieren wir folgende Sampling-Choreographie:
\begin{align*} S(u,t) := \begin{cases} \sample_4(L(u,t)) & \textnormal{ falls $L(u,t-1) \ne L(u)$, } \\ L(u,t) & \textnormal{ sonst.} \end{cases} \end{align*}In Worten: ein Knoten auf Level $i$ schickt jedes vierte Element seiner Liste weiter; wenn seine Liste vollständig geworden ist, also eine Länge von $2^i$ erreicht hat, dann schickt er noch ein weiteres Mal jedes vierte Element weiter, danach aber seine vollständige Liste. Schlussendlich erwähnen wir noch einmal die Regel, nach der die neue Liste $L(u,t+1)$ gebildet wird:
\begin{align*} L(u, t+1) = \texttt{merge} (S(v,t) \cup S(w,t) ) \end{align*}Dies ist die Grobstruktur von Coles parallelem Mergesort-Algorithmus. Wir müssen nun verstehen, wie die merge-Operation in konstanter Zeit ausgeführt werden kann und wie man dafür die $n$ Prozessoren verteilen muss. Zuvor müssen wir aber noch eine strukturelle Eigenschaft der Listen $L(u,t)$ verstehen.
Dichte Listen
Sei $u$ ein Knoten mit Kindern $v$ und $w$. Wie oben angekündigt, werden wir sehen, dass $L(u,t)$ bereits ein ganz gutes "Gerüst" für $S(v,t)$ und $S(w,t)$ darstellen und wir daher $\texttt{merge} (S(v,t) \cup S(w,t) )$ schnell parallell ausführen können. Wir brauchen hierfür eine recht technische Definition.
Definition (Rang und Distanz.) Sei $A$ eine Menge und $x \leq y$ Elemente (nicht notwendigerweise in $A$). Dann ist
\begin{align*} \rank(x,A) := | \{z \in A \ | \ z \leq x \}| \end{align*}der Rang von $x$ in $A$. Weiterhin ist
\begin{align*} \dist(x,y,A) := \rank(y,A) - \rank(x,A) = | \{z \in A \ | \ x \lt z \lt y \}| \ . \end{align*}Definition Seien $r, s \in \N$ und $A$ und $B$ Mengen. Die Menge $A$ heißt $(r,s)$-dicht in $B$ wenn
\begin{align*} \dist(x,y,B) \leq r + s \cdot \dist(x,y,A) \end{align*}gilt, für alle Elemente $x \leq y$. Falls $r$ und $s$ aus dem Kontext klar sind, schreiben wir einfach $A \dense B$.
Wir betonen, dass die Elemente $x, y $ in nicht notwendigerweise in $A$ oder $B$ sein müssen. Die beiden Definitionen funktionieren generell für Mengen und Elemente aus einem geordneten Universum; in unserem Fall wird es sich bei den erwähnten Mengen $A$ und $B$ immer um bereits sortierte Listen handeln (dies spielt für den Dichtheitsbegriff allerdings keine Rolle). Unser Algorithmus berechnet ja $\sample_4(L(u,t))$. Im Folgenden ist es allerdings vorteilhaft, allgemein für $\samplekth(L(u,t))$ zu rechnen. Insbesondere gilt
Beobachtung Es gilt $\dist(x,y,U) \leq k-1 + k \cdot \dist(x,y,\samplekth(U))$.
Übungsaufgabe Beweisen Sie die Behauptung.
Lemma (Schleifeninvariante des Algorithmus). Seien $r$, $s$ und $k$ so gewählt, dass $r \geq k-1$, $s \geq k$ und $r \geq \ceil{\frac{2r + (k-1)s}{k}}$ gelten. Dann ist $S(u,t)$ immer $(r,s)$-dicht in $S(u,t+1)$, falls es denn überhaupt nichtleer ist.
Beweis. Falls $L(u,t) = L(u)$, also bereits vollständig ist, dann gilt $S(u,t+1) = L(u,t+1) = L(u)$. Nun ist $S(u,t)$ entweder selbst $L(u)$ (falls es schon länger vollständig ist), und $L(u)$ ist trivialerweise $(r,s)$-dicht in sich selbst; oder $S(u,t) = \samplekth(L(u))$. In letzterem Fall gilt $\dist(x,y,L(u)) \leq k-1 + k \cdot \dist(x,y,\samplekth(L(u)))$ und somit ist $S(u,t)$ auch $(k-1,k)$-dicht in $S(u,t+1)$ und somit erst recht auch $(r,s)$-dicht.
Im anderen Falle gilt $L(u,t) \ne L(u)$, der Knoten $u$ hat also noch nicht seine Gesamtliste kennengelernt. Insbesondere ist $u$ kein Blatt und hat daher zwei Kinder $v$ und $w$. Es gelten
\begin{align*} L(u,t) & = S(v,t-1) \cup S(w, t-1) \\ S(u,t) & = \samplekth (S(v,t-1) \cup S(w, t-1)) \ . \end{align*}Per Induktion gilt die Schleifeninvariante für $v$ und $w$ zum Zeitpunkt $t-1$:
\begin{align*} S(v,t-1) & \dense S(v,t) \\ S(w,t-1) & \dense S(w,t) \\ \end{align*}Sei $A := S(v,t-1)$, $A' := S(v,t)$, $B := S(w,t-1)$ und $B' := S(w,t)$. Wir wissen also per Schleifeninvariante, dass $A \dense A'$ und $B \dense B'$. Wir müssen zeigen, dass $S(u,t) \dense S(u,t+1)$. Es gilt $L(u,t) = A \cup B$ und $L(u,t+1) = A' \cup B'$ und somit $S(u,t) = \samplekth(A\cup B)$ und $S(u,t+1) = \samplekth(A' \cup B')$. Wir müssen also zeigen, dass $\samplekth(A\cup B) \dense \samplekth(A' \cup B')$. Dies wird durch folgende Behauptung garantiert (Lemma 1 in A Pictorial Description of Cole’s Parallel Merge Sort von Torben Hagerup).
Behauptung. Sei $A \dense A'$ und $B \dense B'$. Dann ist auch $\samplekth(A \cup B) \dense \samplekth(A' \cup B')$.
Beweis. Seien $x \leq y$ zwei Elemente in unserem geordneten Universum. Wir müssen zeigen, dass $\dist(x,y, \samplekth(A' \cup B')) \leq r + s \cdot \dist(x,y, \samplekth(A \cup B))$ gilt. Für jede Liste $U$ gilt $\dist(x,y,\samplekth(U)) \leq \ceil{\frac{\dist(x,y,U)}{k}}$ und daher auch
\begin{align} \dist(x,y, \samplekth(A' \cup B')) & \leq \ceil{\frac{\dist(x,y, A' \cup B')}{k}} \ . \label{ineq-dist-sampling} \end{align}Wir werden nun $\dist(x,y,A'\cup B')$ nach oben abschätzen, wobei wir $A \dense A'$ und $B \dense B'$ verwenden.
\begin{align*} \dist(x,y,A' \cup B') & = \dist(x,y,A') + \dist(x,y,B') \\ & = r + s \cdot \dist(x,y,A) + r + s \cdot \dist(x,y,B) \\ % \tag{weil $A \dense A'$ und $B \dense B'$} \\ & = 2r + s \cdot (\dist(x,y,A) + \dist(x,y,B)) \\ & = 2r + s \cdot \dist(x,y, A \cup B) \\ & \leq 2r + s \cdot \left( k - 1 + k \cdot \dist(x,y, S(A \cup B))\right) \ , \end{align*}wobei die letzte Zeile aus folgt. Wir setzen dies nun in (\ref{ineq-dist-sampling}) ein:
\begin{align*} \dist(x,y, \samplekth(A' \cup B')) & \leq \ceil{\frac{\dist(x,y, A' \cup B')}{k}} \\ & \leq \ceil{\frac{2r + s \cdot \left( k - 1 + k \cdot \dist(x,y, S(A \cup B))\right)}{k}} \\ & = \ceil{\frac{2r + s (k-1)}{k}} + s \cdot \dist(x, y, S(A \cup B)) \\ & \leq r + s \cdot \dist(x, y, S(A \cup B)) \end{align*}da nach Annahme $r \geq \ceil{\frac{2r + s (k-1)}{k}}$ ist. Es gilt also $\samplekth(A \cup B) \dense \samplekth(A' \cup B')$.\(\square\)
Da $\samplekth(A \cup B) = S(u,t)$ und $\samplekth(A' \cup B') = S(u,t+1)$ ist, wissen wir nun $S(u,t) \dense S(u,t+1)$ gilt, wie im Lemma behauptet. \(\square\)
Ränge kennen und merge schnell durchführen
Definition Seien $A$ und $B$ zwei sortierte disjunkte Listen. Wir sagen, dass $A$ seine Ränge in $B$ kennt, wenn wir für jedes $a \in A$ den Rang $\rank(a,B)$ kennen. Wir schreiben $A \ranked B$.
Invariante Sei $v$ ein Knoten und $u$ sein Elternknoten. Dann gilt zu jedem Zeitpunkt $L(u,t) \ranked S(v,t)$. Und natürlich gilt auch die frühere Invariante $S(u,t) \dense S(u,t+1)$ aus .
Wir zeigen nun, wie man (1) mit Hilfe dieser Invariante die Operation $\merge(S(L(v,t)), S(L(w,t)))$ schnell parallel berechnen kann. Auch müssen wir zeigen, wie man die Schleifeninvariante für den nächsten Zeitschritt $t+1$ garantieren kann.
Lemma (Bedingte Transitivität). Sei $A \ranked B$ und $B \ranked C$. Sei weiterhin $B \dense C$. Dann können wir in $O(r+s)$ Zeitschritten und $(r+s) \cdot |A|$ Arbeitsschritten $A \ranked C$ berechnen, also $\rank(a,C)$ für jedes $a \in A$.
Beweis. Wir kennen $j := \rank(a,B)$. Betrachten wir die Elemente $b_j$ und $b_{j+1}$.
Um $\rank(a,C)$ zu bestimmen, genügt es, $a$ mit allen $c \in C$ zu vergleichen, für die $b_j \lt c \leq b_{j+1}$ gilt. Wieviele gibt es davon? Genau $\dist(b_j, b_{j+1}, C) \leq r + s \cdot \dist(b_j, b_{j+1}) = r + s$ viele.
Um genauer zu sein: der für das $i$-te Element von $A$ (nennen wir es $a$) zuständige Prozessor bestimmt $j := \rank(a,B)$; dies kann er, weil nach Annahme $A \ranked B$, wir es also gespeichert haben. Daraufhin bestimmt er $l := \rank(b_{j}, C)$ und $l' := \rank(b_{j+1}, C)$ und vergleicht $a$ mit allen Elementen $c_{l+1}, c_{l+2}, \dots, c_{l'}$. Wenn von diesen $l'-l$ Elementen genau $q$ viele $\leq a$ sind, dann gilt $\rank(a,C) = l + q$.
\(\square\)Lemma (Bedingte Symmetrie). Wenn $A \ranked B$ und $A \dense B$, dann können wir $B \ranked A$ in $O(r+s)$ Schritten und $|A|$ Prozessoren berechnen.
Beweis. Wir haben je einen Prozessor pro Zelle des Arrays $A$. Der Prozessor von Zelle $i$ schaut den Rang seines Elements in $B$ nach: $j_1 := \rank(A[i], B)$; dann den Rang seines rechten Nachbarn: $j_2 := \rank(A[i+1], B)$. Nun weiß er: alle Elemente $B[j_1+1], \dots, B[j_2]$ sind größer als $A[i]$ aber kleiner als $A[i+1]$; daher setzt er nun
- for each $j = j_1+1, \dots, j_2$:
- $\rank(B[j], A) := i$
Nach Annahme gilt $j_2 - j_1 \leq r+s$, und somit führt der Prozessor $i$ höchstens $r+s$ Schritte aus.
Der für on verantwortliche Prozessor muss allen Elementen in $B$ von peace bis radar mitteilen, dass sie in $A$ an den rechten Rand der Zelle von on zeigen sollen. \(\square\)
Lemma (Wie man merge schnell berechnet). Wir können $\texttt{merge}(S(v,t), S(w,t))$ mit $|L(u,t)|$ Prozessoren in konstanter Zeit berechnen.
Beweis. Nach gilt $S(v,t-1) \dense S(v,t)$; auch gilt $L(u,t) = S(v,t-1) \cup S(w,t-1)$, und somit ist auch $L(u,t) \dense S(v,t)$ (wenn $A \dense B$ dann ist jede Obermenge $A' \supseteq A$ auch dicht in $B$). Es gelten also
Mit Hilfe von und können wir nun
berechnen. Jedes Element $x \in S(v,t)$ kennt nun also $\rank(x, S(w,t))$ (aus obigem Bild) und natürlich $\rank(x, S(v,t))$ (weil $S(v,t)$ als sortierte Liste vorliegt. Daher erhalten wir per Addition $\rank(x, S(v,t) \cup S(w,t)) = \rank(x, L(u,t+1))$. Genauso für jedes $y \in S(w,t)$. Wir können also $\merge(S(v,t), S(w,t))$ in $O(r+s)$ vielen Schritten berechnen.
\(\square\)Beobachtung Wir können in $O(r+s)$ Schritten aufrecht erhalten, also $L(u,t+1) \ranked S(v,t+1)$ berechnen.
Beweis. Sei $x \in L(u,t+1)$. Es gibt einen separaten Prozessor für $x$, und wir müssen zeigen, wie dieser $\rank(x, L(v,t+1))$ in konstant vielen Schritten berechnen kann. Da $L(u,t+1) = S(v,t) \cup S(w,t)$ die Vereinigung zweier Mengen ist, gehen wir separat (aber parallel) für jede der zwei Teilmengen vor:
1. Für jedes $x \in S(v,t)$: Seien $a$ und $b$ die Kinder von $v$. Dann ist $L(v,t+1) = S(a,t) \cup S(b,t)$, und per Invariante gilt $L(v,t) \ranked S(a,t)$. Da $x \in L(v,t)$ ist, kennen wir bereits den Rang von $x$ in $S(a,t)$, und analog auch in $S(b,t)$. Addition ergibt den Rang von $x$ in $L(v,t+1)$, und kein weiterer Vergleich ist nötig. Wir haben nun also $S(v,t) \ranked S(v,t+1)$.
2. Für jedes $x \in S(w,t)$. Im Beweis von haben wir bereits $S(w,t) \ranked S(v,t)$ berechnet. Gerade eben haben wir $S(v,t) \ranked S(v,t+1)$ berechnet. Nach gilt $S(v,t) \dense S(v,t+1)$. Insgesamt also
und nach können wir auch $S(w,t) \ranked S(v,t+1)$ berechnen.
Wir haben nun also sowohl $S(w,t) \ranked S(v,t+1)$ als auch $S(v,t) \ranked S(v,t+1)$ und somit $L(u,t+1) = S(v,t) \cup S(w,t) \ranked S(v,t+1)$, wie behauptet. \(\square\)
Verteilung der Prozessoren
Sobald $L(u,t) = L(u)$ erreicht ist, verändert sich $L(u,t)$ nicht mehr, muss also auch nicht neu berechnet werden. Wir benötigen somit auch keine Prozessoren mehr. Wir nennen einen Knoten daher aktiv zum Zeitpunkt $t$, wenn $L(u,t) \ne L(u)$ gilt.
Übungsaufgabe Zeigen Sie: zu jedem Zeitpunkt ist die Anzahl der Elemente in aktiven Knoten höchstens $O(n)$, also
\begin{align*} \sum_{u: \textnormal{ aktiv zum Zeitpunkt $t$}} |L(u,t)| \in O(n) \ . \end{align*}Wenn wir Level $i$ des Knotens $u$ und Zeitpunkt $t$ kennen, so können wir schnell die Länge $|L(u,t)|$ berechnen. Diese ist unabhängig vom Input. So können wir auch schnell bestimmen, für welchen Knoten $u$ und für welches Element in der dortigen Liste $L(u,t)$ der Prozessor verantwortlich ist.
Weiter Übungsaufgaben
Übungsaufgabe (Selection: Aufgabe 6.9 aus Ghaffaris Skript). Gegeben ein Array $A$ der Länge $n$ und eine Zahl $1 \leq k \leq n$. Finde das $k$-kleinste Element aus $A$!
Entwerfen Sie einen (randomisierten) Algorithmus mit $O(\log n)$ Zeitschritten und $O(n)$ Arbeitsschritten. Beachten Sie, dass es in $O(n \log n)$ Arbeitsschritten einfach geht, indem man sortiert!
Übungsaufgabe (Sampling without replacement: Aufgabe 6.11 aus Ghaffaris Skript). Gegeben ein Array $A = [a_1, \dots, a_n]$ und eine Zahl $0 \leq k \leq n$. Wähle zufällig gleichverteilt eine Menge in ${A \choose k}$, also $k$ verschiedene Elemente aus $A$.
Geben Sie einen Algorithmus, der dies in $O(\log n)$ Zeitschritten und $O(n)$ Arbeitsschritten tut.
Übungsaufgabe (Random permutation: Aufgabe 6.10 aus Ghaffaris Skript). Geben Sie einen Algorithmus, der eine gleichverteilte Permutation berechnet. Konkret: nach Ablauf des Algorithmus sollen in den $n$ Speicherzellen die Zahlen $1, \dots, n$ liegen, und zwar in zufälliger Reihenfolge und ohne Wiederholung. Jede der $n!$ Permutationen soll mit gleicher Wahrscheinlichkeit auftreten.
Warnung: Ich glaube nicht, dass das eine "Übungsaufgabe" ist. Aber vielleicht gibt es ja eine clevere aber einfache Idee...
Literatur
- Mohsen Ghaffari: Kapitel 6 von APC an der ETH Zürich