Teile und Herrsche 1 WS13-14

Aus ProgrammingWiki
< AuK
Archivierte Version vom 2013-10-26T08:19:38+00:00. Aktuelle Version

Inhaltsverzeichnis

Autoren:

Vorbetrachtungen

Grundsätzliches

  • Ein großes Problem wird in in kleinere Teilprobleme zerlegt (teile - divide).
  • Teilprobleme werden einzeln gelöst (herrsche - conquer).
  • Zusammensetzen der einzelnen Lösungen zu einer Gesamtlösung.

Beispiele allgemein und aus der Informatik

  • Das Programmingwiki: Das große Problem der Veranstaltung Algorithmen wird aufgeteilt (Themen) und diese zerlegten Teilprobleme von einzelnen (Studenten) bearbeitet und gelöst(Referat). Am Ende werden die einzelnen Lösungen zusammengefügt und bilden die Lehrveranstaltung Algorithmen und Komplexität.
  • Beim Sortieren: Es ist eine Gesamtliste L gegeben mit n Elementen, also L = (e_{1}, e_{2},..., e_{n}), welche nach der göße der Elemente Sortiert werden soll. Man teilt die Liste auf und sortiert die Teillisten nach der Größe und fügt die geortneten Listen in der richtigen Reihenfolge wieder zusammen.

Effizienzbetrachtung von Teile und Herrsche

Es wird erhofft das diese Technik effizienter ist als das Lösen des Gesamtproblems ohne es zu zerlegen.

Angenommen, ein Algorithmus \mathcal{A} löst das Problem in \mathcal{O}\left(n^{2}\right),d.h. mit \mathit{T}_{\mathcal{A}}\left(n\right)\leq c\cdot n. Für den Gesamtaufwand \mathit{T}_{\mathcal{B}} eines Algorithmus \mathcal{B}, der beispielsweise drei dieser Probleme der Größe \frac{n}{2} mittels Prozedur \mathcal{A} bearbeitet, um die Teillösungen anschließend mit dem Aufwand in \mathcal{O}\left(n\right) zusammenzufügen, gilt damit:

\begin{align} \begin{array}{rcl} T_{B} \left( n \right) & = & 3 \cdot T_{A} \cdot\left(\lceil\frac{n}{2} \rceil \right) + d \cdot n\\\\

                & \leq & 3 \cdot c \cdot \left( \frac{n+1}{2}\right) ^{2} + d \cdot n\\\\
                & \leq & 3 \cdot c \cdot \left( \frac{n+1}{2}\right) \left( \frac{n+1}{2}\right) + d \cdot n\\\\
                & \leq & 3 \cdot c \cdot \left( \frac{n^{2} + 2n + 1}{4}\right) + d \cdot n\\\\
                & \leq & 3 \cdot c \cdot \left( \frac{n^{2}}{4} + \frac{2n}{4} + \frac{1}{4}\right) + d \cdot n\\\\
                & \leq & \frac{3cn^{2}}{4} + \frac{6cn}{4} + \frac{3c}{4} + d \cdot n\\\\
                & \leq & \frac{3}{4}cn^{2} + \frac{3}{2}cn + \frac{3}{4}c + d \cdot n\\\\
                & \leq & \frac{3}{4}cn^{2} + \left(\frac{3}{2}c + d\right) \cdot n + \frac{3}{4} c\\\\

\end{array} \end{align}

Man erkennt an den führenden Summanden, das es tatsächlich eine Effizienzsteigerung von ca. 25% ergibt. Aber es ergibt sich immer noch ein quadratischer Aufwand mit \mathcal{O}\left(n^{2}\right). Daher betrachten wir nun einen Algorithmus \mathcal{C}, welcher das Problem auf rekursive Art löst.

\begin{align} \mathit{T}_{\mathcal{C}}\left(n\right) = \begin{cases} \mathit{T}_{\mathcal{A}}\left(n\right), \mbox{wenn}\ n\leq n_{0} \\ \mathit{3\ T}_{\mathcal{C}}\left(\dfrac{n}{2}\right), \mbox{sonst}\end{cases} \end{align}

Nach dem Lösen dieser Formel kommen wir zu dem Ergebnis \mathit{T}_{\mathcal{C}}\left(n\right)=\mathcal{O}\left(n^{1.59}\right).

Quicksort

Der Quicksort Algorithmus wurde 1962 von C.A.O. Hoare angegeben. Der Grundgedanke ist eine Liste L = (e_{1}, e_{2},\dots, e_{n}) in zwei Teillisten zu zerlegen. Eine linke Teilliste TL und eine rechte Teilliste TR. Diese Listen werden durch einen Vergleich mit einem Pivotelment (Vergleichselement) v gebildet. dabei muss \mathit{v} \in G gelten. Es wird verabredet das alle Elemente von L paarweise verschieden sind, also m \neq n also gilt e_{m} \neq e_{n}. Dies ist zwar nicht erforderlich aber im Allgemeinen sinnvoll, da es normalerweise um Schlüssel zur Identifikation von Datenätzen handelt. Weiterhin wird verabredet das es sich um eine Liste mit natürlichen Zahlen handelt. Eine weitere Festlegung, das am weitesten links stehende Element aus L als v zu nehmen, das bedeutet \mathit{v} = e_{1}. Die sortierte Gesamtliste L_{sortiert} entsteht durch die Teilliste TL_{sortiert}, \mathit{v} und TR_{sortiert}. in dieser Reihenfolge. Die Abarbeitung der Teillisten findet dabei Rekursiv statt. Die zwei Elementarfälle: Ist L leer oder hat nur ein einzelnes Element, dann ist L = L_{sortiert}. Bei der Teilung der Liste L in TL und TR entstehen wieder Listen die mindestens L-1 Elemente enthalten, da v entfernt wurde. Es wird nah endlich vielen Zerlegungen einer der Elementarfälle erreicht.

Funktionaler Aufbau

Hierbei entstehen 2 Teillisten um eine sortierte Liste zu bekommen benötigen wir noch eine weitere Prozedur.

Effizienz von Quicksort

best case

Quicksort arbeitet am effektivsten wenn die zu sortierenden Teillisten etwa gleich lang sind.

\begin{align} \mathit{T}\left(0\right) &= 0\notag\\ \mathit{T}\left(n\right) &= 2 \cdot \mathit{T}\left(\frac{n}{2}\right) + c \cdot n\notag \end{align}

Dabei kommen wir auf einen Aufwand von \mathit{T}\left(n\right)= \mathcal{O}\left(n \log_{2} n\right).

worst case

Dieser Fall ist etwas sonderbar, da hier eine vollständig sortierte Liste schon vorliegt und das Ergebnis eigentlich schon entsprechend vorhanden ist. Hier ist die Rekursionsgleichung:

\begin{align} \mathit{T}\left(0\right) &= 0\notag\\ \mathit{T}\left(0\right) &= \underbrace{\mathit{T}\left(0\right)}_\text{= 0} + \mathit{T}\left(n - 1\right) + c \cdot n\notag \end{align}

Diese Gleichung kann iterativ gelöst werden.

\begin{align} \mathit{T}\left(n - 1\right) &= \mathit{T}\left(n - 2\right) + c \left(n - 1\right)\notag\\ \mathit{T}\left(n - 2\right) &= \mathit{T}\left(n - 3\right) + c \left(n - 2\right)\notag\\\\ \vdots \\\\ \mathit{T}\underbrace{\left(\ n - k \ \right)}_{\text{ = 1 \curvearrowright k = n - 1}} &= \mathit{T}\left(0\right) + c \left(n - k\right)\notag\\ \end{align}

Setzt man jeden Ausdruck in die Klammer ein, so kommt man auf

\begin{align} \begin{array}{rcl} T(n) &=& c \cdot \sum\limits_{k=0}^{n-1} \left(n-k\right)\\\\ &=& c\cdot(\sum\limits_{k=0}^{n-1} n - \sum\limits_{k=0}^{n-1} k)\\\\ &=& c\cdot\left(n^2 - \frac {n-1}{2}\left(\left(n-1\right)+1\right)\right)\\\\ &=& c\cdot\left(n^2 - \frac {n^2 -n}{2}\right)\\\\ &=& c\cdot\left(\frac {n^2} {2} + \frac {n} {2}\right) \\\\\\ T(n) &=& \mathcal{O}\left(n^2\right)\\\\ \end{array}\notag \end{align}

average case

Hier wird davon ausgegangen das jede der \mathit{n} Teillistenlängen mit der gleichen Wahrscheinlichkeit auftritt, nämlich \dfrac{1}{n}. Dann gilt:

\begin{align} \begin{array}{rcl} T(i) = T\left(n-i-1\right) = \frac {1}{n} \cdot \sum\limits_{j=0}^{n-1} T\left( j\right)\\\\ T(n) = \underbrace{T\left(i\right)}_{linke\ Teilliste} + \underbrace{T\left(n-i-1\right)}_{rechte\ Teilliste} + \underbrace{c \cdot n}_{Teillistenbildung}\\\\ \end{array} \end{align}

Setzt man dies dann ein, so ergibt sich folgendes:

\begin{align} \begin{array}{rcl} T\left(n\right) &=& \frac {2}{n} \sum\limits_{j=0}^{n-1} T\left(j\right) + c \cdot n\\\\ \end{array} \end{align}

Nun wird die Summe beseitigt, dazu bilden wir Differenzen.

\begin{align} \begin{array}{rcl} nT\left(n\right) &=& 2 \sum\limits_{j=0}^{n-1} T\left(j\right) + c \cdot n^{2} \\\\ \left(n-1\right)T\left(n-1\right) &=& 2 \sum\limits_{j=0}^{n-2} T\left(j\right) + c \cdot \left(n-1\right)^2 \mid \text{für} \ n:=n - 1; -\\\\ \\\\ nT\left(n\right) - \left(n-1\right)T\left(n-1\right) &=& 2T\left(n-1\right) + 2cn - c \mid -c\ \text{entfällt für}\ n \rightarrow \infty\\\\ \frac{T\left(n\right)}{n+1} &=& \frac{T\left(n-1\right)}{n} + \frac{2c}{n+1}\\\\ \frac {T\left(n-1\right)}{n} &=& \frac{T\left(n-2\right)}{n-1} + \frac{2c}{n}\\\\ \vdots & & \vdots\\\\ \frac{T\left(2\right)}{3} &=& \frac{T\left(1\right)}{2} + \frac{2c}{3}\\\\ \\\\ \frac{T\left(n\right)}{n+1} &=& \underbrace{\frac{T\left(1\right)}{2}}_{=0, da\ T\left(1\right) =0} + 2 \sum\limits_{i=3}^{n+1} \frac{1}{i}\\\\ \end{array} \end{align}

Bei der Benutzung der bekannten Schranken \frac {\lfloor log_{2} \ n \rfloor +1}{2} < \mathit{H}_{n} \leq \lfloor log_{2} \ n \rfloor +1 für die Harmonischen Zahlen \mathit{H}_{n} = \sum\limits_{k=1}^{n} \frac{1}{k}.

\begin{align} \frac {T\left(n\right)}{n+1} = \mathcal{O} \left(log_{2} \ n\right)\curvearrowright T\left(n\right) = \mathcal {O} \left(n \cdot log_{2} \ n\right) \end{align}

Die Effizienz von Quicksort in allen drei Fällen:

\begin{align} \begin{array}{|c|c|} \hline best \ case & \Theta\left(n \ \log_{2} n\right) \\ \hline average \ case & \mathcal{O}\left(n \ \log_{2} n\right) \\ \hline worst \ case & \Omega\left(n^{2}\right) \\ \hline \end{array} \end{align}

Mergesort

Mergesort und Quicksort sind eng miteinander Verwandt, Merge kann mit Zusammenführen übersetzt werden. Eine zu sortierende Gesamtliste

L = \left(Le_{1}, Le_{2}, Le_{3}, \cdots , Le_{n}, Re_{1}, Re_{2}, Re_{3}, \cdots , Re_{m}\right)

wird in zwei etwa gleich große Teillisten,

TL= \left(Le_{1}, Le_{2}, Le_{3}, \cdots , Le_{n}\right) und TR= \left(Re_{1}, Re_{2}, Re_{3}, \cdots , Re_{m}\right)

geteilt.

n = |L|\div 2 = m\div 2.

Es wird kein Vergleich oder Vorsortierung vorgenommen.Das \div Zeichen steht für eine ganzzahlige Division. Es gilt entweder m = 2n oder m = 2n +1. Dann werden die beiden Teillisten rekursiv, das bedeutet mit Mergesort, sortiert. Die Elementarfälle sind die selben wie bei Quicksort. Der dritte Schritt besteht darin, die sortierten Teillisten mit einem Reißverschlusssystem wieder zusammenzufügen. Die jeweiligen führenden Teilelemente Le_{i} und Re_{j} gelangen an ein "Tor", wenn Le_{i} < Re_{j} gilt wird Le_{i} durchgelassen und nimmt die nächste freie Position in der Gesamtliste ein. Re_{j} wird dann mit Le_{i+1} verglichen. Ansonsten natürlich umgekehrt.