• Keine Ergebnisse gefunden

Kapitel03:Sortieren AlgorithmenundDatenstrukturen

N/A
N/A
Protected

Academic year: 2022

Aktie "Kapitel03:Sortieren AlgorithmenundDatenstrukturen"

Copied!
70
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Algorithmen und Datenstrukturen

– Wintersemester 2019 –

Kapitel 03:

Sortieren

Fachbereich Informatik TU Kaiserslautern

Dozent: Dr. Patrick Michel

Folien urspr¨unglich von Prof. Dr. Adrian Ulges (Hochschule RheinMain)

12. November 2019

1

(2)

Sortieren: Motivation

Warum ist Sortieren wichtig?

1. Praxisrelevanz

Sortieren ist praxisrelevant: 25% aller Rechenzeitentf¨allt auf Sortiervorg¨ange1.

Beispiele: Datenbanken, Suchmaschinen, ...

2. Didaktik

Sortieren ist dasEinf¨uhrungsproblemder Algorithmik.

Es gibt eine Vielfalt an Ans¨atzen.

Viele Standardkonzepte werden behandelt(O-Notation,

Rekursion, Divide-and-Conquer, untere Schranken, ...)

1Sch¨atzung aus den 1960er Jahren... Trotzdem auch noch heute wichtig!

2

(3)

Sortieren: Formalisierung

Praxis

In der Praxis sortieren wir

beliebige Objekte (z.B. Kunden).

Diese Objekte enthalten jeweils einenSchl¨ussel(z.B. Umsatz) und Nutzinformation(Kundennummer, Name, Adresse, ...).

DerSchl¨usseldefiniert eineOrdnungsrelation auf Objekten.

Vorlesungsfolien: Reduktion aufs Wesentliche

Waswir sortieren ist eigentlich irrelevant: Wir ben¨otigen nur Objekte mit einer gegebenenOrdnungsrelation. Wir vereinfachen:

Die Objekte sind int-Zahlen.

die Ordnungsrelation ist≤ / ≥.

die Nutzdaten entfallen.

3

Nutz- information Schlüssel

Sicht in der Praxis Sicht in ADS

int

(4)

Sortieren: Formalisierung

Gegeben

Ein n-elementiges Array von ganzen Zahlena[0], ...,a[n−1] (oder a[1], ...,a[n]).

Gesucht

Eine Permutation π∶ {0, ...,n−1} → {0, ...,n−1} so dass a[π(0)] ≤a[π(1)] ≤...≤a[π(n−1)]

Beispiel (rechts): π= (3,6,8,4,0,7,1,9,2,5) Anmerkungen

Die obige Problemstellung nennen wir aufsteigendes Sortieren. Bei absteigendemSortieren fordern wir

a[π(0)] ≥a[π(1)] ≥...≥a[π(n−1)]

Wir messen dieLaufzeitvon Sortieralgorithmen als die Anzahl der Vergleicheund/oderLese-/Schreibzugriffe auf das Array.

4

11 17 23 2 7 29 3 13 5 19

0 1 2 3 4 5 6 7 8 9

a (unsortiert)

2 3 5 7 11 13 17 19 23 29

a (sortiert)

0 1 2 3 4 5 6 7 8 9

(5)

Sortieren: Grundannahmen

1. Internes Sortieren

Wir nehmen an: Alle Daten befinden sich imHauptspeicher

→Lesezugriffe aufa[i] sind g¨unstig (O(1)).

Gegenteil:Externes Sortieren: Die Daten befinden sich auf einem externen, langsamen Speicher2 (z.B. Festplatte).

2. G¨unstige Vergleiche

Eine Auswertung der Ordnungsrelation ist g¨unstig (O(1)).

Gegenbeispiel: Stringvergleich (O(length(string))).

3. G¨unstige Schreibzugriffe

Die ¨Anderung von Werten (a[i]=c) sind g¨unstig (O(1)).

Gegenbeispiel: Datenbanken ( ¨Anderungen k¨onnen Reorganisation ausl¨osen, O(n)).

2siehe auchLatency Numbers Every Programmer Should Know[4].

5

(6)

Outline

1. Einfache Verfahren: Insertionsort

2. Einfache Verfahren: Selectionsort 3. Einfache Verfahren: Bubblesort 4. Effiziente Verfahren 1: Mergesort 5. Effiziente Verfahren 2: Quicksort 6. Effiziente Verfahren 3: Heapsort

7. Effiziente Verfahren 4: Radix Exchange Sort 8. Stabilit¨at von Sortierverfahren

9. Untere Schranke 10. Externes Sortieren 11. Abschlussbemerkungen

6

(7)

Insertionsort

Wir behandeln zun¨achst einige einfache, weniger effiziente Sortierverfahren:Insertionsort,Selectionsort,Bubblesort.

Insertionsort

Annahme: Die linke Seite des Arrays (a[0],...,a[pos-1]) ist bereitssortiert.

In jedem Schleifendurchlauf f¨ugen wir a[pos] an der richtigen Stellein den sortierten Bereich ein. Der sortierte Bereich ist jetzt um ein Feld gr¨oßer

(a[1],...,a[pos]).

Am Ende ist das komplette Array sortiert.

7

1117 23 2 7 29 3 13 5 19 111723 2 7 29 3 13 5 19 11 1723 2 7 29 3 13 5 19 11 17 23 2 7 29 3 13 5 19 2 11 17 23 7 29 3 13 5 19 2 7 11 17 2329 3 13 5 19 2 7 11 17 23 29 3 13 5 19 2 3 7 11 17 23 2913 5 19 2 3 7 11 13 17 23 29 5 19 2 3 5 7 11 13 17 23 2919 2 3 5 7 11 13 17 19 23 29

0 1 2 3 4 5 6 7 8 9 pos

0 1 2 3 4 5 6 7 8 9 10

(8)

Insertionsort: Pseuco-Code

Ablauf

In der inneren Schleife (i) werden – beginnend beipos – alle Elemente gr¨oßer a[pos] um eins nach rechtsverschoben.

a[pos] wird an der richtigen Stellewieder eingef¨ugt.

Die innere Schleife wird verlassen.

8

# Gegeben: Array a = a[0],a[1],...,a[n-1]

for pos = 1,.., n-1:

value = a[pos]

# Verschiebe alle Werte > value # um 1 nach rechts

for i = pos, pos-1, ..., 0:

if i>0 and a[i-1]>value:

a[i] = a[i-1]

else:

# Füge value an der # richtigen Stelle ein ...

a[i] = value

# und beende innere Schleife break

2 3 7 11 17 23 2913 5 19 2 3 7 11 17 23 29 19

0 1 2 3 4 5 6 7 8 9

i 7 6 5 4

value=13

5 2 3 7 11 17 23 29 5 19 2 3 7 11 17 23 29 5 19 2 3 7 11 17 23 29 5 19

value=13

13

(9)

Insertionsort: Aufwands-Analyse

Wir berechnen die Worst-Case-Laufzeit (= Anzahl derVergleiche) f(n). Es seiginner(pos) die Anzahl

der Vergleiche ineinem Durchlauf der inneren Schleife

(in Abh¨angigkeit von pos).

9

# Gegeben: Array a = a[0],a[1],...,a[n-1]

for pos = 1,.., n-1:

value = a[pos]

# Verschiebe alle Werte > value # um 1 nach rechts

for i = pos, pos-1, ..., 0:

if i>0 and a[i-1]>value:

a[i] = a[i-1]

else:

# Füge value an der # richtigen Stelle ein ...

a[i] = value

# und beende innere Schleife break

(10)

Insertionsort: Diskussion

Insertionsort besitztquadratische Komplexit¨at./

Beispiel: Benchmark einer Java-Implementierung (Insertionsort auf Zufallszahlen).

Wir sehen: Verzehnfacht sich n, verhundertfachen sich (grob) Vergleiche und ¨Anderungen.

10 62 Vergleiche 27 Änderungen 0.00 secs 100 5124 Vergleiche 2516 Änderungen 0.00 secs 1000 505613 Vergleiche 252311 Änderungen 0.02 secs 10000 50393577 Vergleiche 25191792 Änderungen 0.09 secs 20000 200660443 Vergleiche 100320226 Änderungen 0.17 secs 40000 797198244 Vergleiche 398579124 Änderungen 1.15 secs 60000 1806771971 Vergleiche 903355989 Änderungen 1.31 secs 100000 5012503054 Vergleiche 2506201529 Änderungen 3.72 secs

x 10 x 100 x 100

Feldlänge n #Vergleiche #Änderungen Laufzeit (Sek.)

Was macht Insertionsort aufw¨andig?

Insertionsort ben¨otigt im Vergleich zu anderen Sortierverfahren besonders viele Schreibzugriffe!

Jedes Mal, wenn das Elementa[pos]ganz vorne eingef¨ugt wird, erfolgen posSchreibzugriffe!

10

(11)

Outline

1. Einfache Verfahren: Insertionsort 2. Einfache Verfahren: Selectionsort

3. Einfache Verfahren: Bubblesort 4. Effiziente Verfahren 1: Mergesort 5. Effiziente Verfahren 2: Quicksort 6. Effiziente Verfahren 3: Heapsort

7. Effiziente Verfahren 4: Radix Exchange Sort 8. Stabilit¨at von Sortierverfahren

9. Untere Schranke 10. Externes Sortieren 11. Abschlussbemerkungen

11

(12)

Selectionsort

Ansatz

Bestimme daskleinste Element und tausche es an Position 0.

Tausche das n¨achstkleinste Element an Position 2.

Tausche das n¨achstkleinste Element an Position 3.

...

Pseudo-Code

# Gegeben: Array a = a[0],a[1],...,a[n-1]

for pos = 0,.., n-1:

min := die Position des Minimums von a[pos],a[pos+1],...,a[n-1]

Vertausche a[pos] und a[min]

12

11 17 23 2 7 29 3 13 5 19 2 3 23 11 7 29 17 13 5 19 2 3 5 11 7 29 17 13 23 19 2 3 5 7 11 29 171323 19 2 3 5 7 1129 17 13 23 19 2 17 23 11 7 29 3 13 5 19 11 17 23 2 7 29 3 13 5 19

2 3 5 7 11 131729 23 19 2 3 5 7 11 13 17 192329 2 3 5 7 11 13 17 19 5 29 2 3 5 7 11 13 17 29 2319

2 3 5 7 11 13 17 19 23 29

0 1 2 3 4 5 6 7 8 9

pos 0 1 2 3 4 5 6 7 8 9 10

(13)

Outline

1. Einfache Verfahren: Insertionsort 2. Einfache Verfahren: Selectionsort 3. Einfache Verfahren: Bubblesort

4. Effiziente Verfahren 1: Mergesort 5. Effiziente Verfahren 2: Quicksort 6. Effiziente Verfahren 3: Heapsort

7. Effiziente Verfahren 4: Radix Exchange Sort 8. Stabilit¨at von Sortierverfahren

9. Untere Schranke 10. Externes Sortieren 11. Abschlussbemerkungen

13

(14)

Bubblesort: Ansatz

Es seipos=n-1 eine “Endposition”.

Wir durchlaufen das Array von vorne bispos. Immer wenn zwei benachbarte Elementein falscher Reihenfolge sind,vertauschenwir sie.

Hierbei “steigt” das gr¨oßte Element des Arrayswie eine Blasean die letzte Stelle.

Wir wiederholen den Durchlauf, diesmal bispos = n-1. Danach befindet sich das zweitgr¨oßte Element an vorletzter Stelle.

Wir wiederholen den Durchlauf mit pos = n-2.

...

14

11 17 23 2 7 29 3 13 5 19

11 17 2 23 7 29 3 13 5 19

11 17 2 7 2329 3 13 5 19 11 17 2 7 23 3 29 13 5 19 11 17 2 7 23 3 1329 5 19 11 17 2 7 23 3 13 5 2919 11 17 2 7 23 3 13 5 1929 17 1123 2 7 29 3 13 5 19

pos=9

0 1 2 3 4 5 6 7 8 9

(Ende)

1117 23 2 7 29 3 13 5 19 11 1723 2 7 29 3 13 5 19

i = 1 2 3 4

7 8 9 11 17 2 23 7 29 3 13 5 19 11 17 2 7 23 29 3 13 5 19 11 17 2 7 23 29 3 13 5 19 5

6 11 17 2 7 23 3 29 13 5 19 11 17 2 7 23 3 13 29 5 19

11 17 2 7 23 3 13 5 2919

(15)

Bubblesort: Pseudo-Code

15

# Gegeben: Array a = a[0],a[1],...,a[n-1]

Für alle Endpositionen pos = n-1, n-2,... 1:

Durchlaufe das Array von i = 1 bis pos An jeder Stelle i:

Falls a[i] < a[i-1]:

Vertausche beide.

pos=8

0 1 2 3 4 5 6 7 8 9

(Ende)

pos=7

0 1 2 3 4 5 6 7 8 9

(Ende)

11 2 7 17 3 13 5 192329

...

2 11 7 17 3 13 5 192329 2 7 1117 3 13 5 192329 2 7 11 3 17 13 5 192329 2 7 11 3 1317 5 192329 2 7 11 3 13 5 17192329 1117 2 7 23 3 13 5 1929 11 2 17 7 23 3 13 5 1929 11 2 7 1723 3 13 5 1929 11 2 7 17 3 23 13 5 1929 11 2 7 17 3 1323 5 1929 11 2 7 17 3 13 5 231929 11 2 7 17 3 13 5 192329

(16)

Bubblesort: Optimierung

Wenn wir Gl¨uck haben, ist das Array bereits ab einer Position i < possortiert.

Woran erkennen wir dies?

Ab einer bestimmten Position pos wurdekein Tausch mehr durchgef¨uhrt!

Was bringt das?Wir k¨onnen possofort auf pos setzen und uns einige Iterationen sparen!

16

pos=9

0 1 2 3 4 5 6 7 8 9

(Ende)

pos=3

0 1 2 3 4 5 6 7 8 9

(Ende)

3 5 2 7 11 13 17192329 ...

3 5 11 2 7 13 17 19 23 29 3 5 2 11 7 13 17 19 23 29 3 5 2 7 1113 17 19 23 29 11 3 5 2 7 13 17 19 23 29 3 11 5 2 7 13 17 19 23 29

Keine Tauschs (rot) nötig

→ Bereich ist schon sortiert.

Wir können ihn überspringen.

→ Setze pos = 3

(17)

Bubblesort: Optimierung

17

# Gegeben: Array a = a[0],a[1],...,a[n-1]

pos = n-1 Wiederhole:

Durchlaufe das Array von i=1 bis pos pos' = 0

An jeder Stelle i:

falls a[i] < a[i-1]:

Vertausche beide.

pos' = i-1 pos = pos' bis pos < 1

pos=9

0 1 2 3 4 5 6 7 8 9

(Ende)

pos=3

0 1 2 3 4 5 6 7 8 9

(Ende)

3 5 2 7 11 13 17192329 3 5 11 2 7 13 17 19 23 29 3 5 2 11 7 13 17 19 23 29 3 5 2 7 1113 17 19 23 29 11 3 5 2 7 13 17 19 23 29 3 11 5 2 7 13 17 19 23 29

3 2 5 7 11 13 17192329 pos=1

0 1 2 3 4 5 6 7 8 9

(Ende)

3 2 5 7 11 13 17192329 2 3 5 7 11 13 17192329 pos=0 → Ende.

(18)

Outline

1. Einfache Verfahren: Insertionsort 2. Einfache Verfahren: Selectionsort 3. Einfache Verfahren: Bubblesort 4. Effiziente Verfahren 1: Mergesort

5. Effiziente Verfahren 2: Quicksort 6. Effiziente Verfahren 3: Heapsort

7. Effiziente Verfahren 4: Radix Exchange Sort 8. Stabilit¨at von Sortierverfahren

9. Untere Schranke 10. Externes Sortieren 11. Abschlussbemerkungen

18

(19)

Mergesort

19

(20)

Mergesort

Die bisher vorgestellten Suchverfahren besitzen eine

Worst-Case-Komplexit¨atvon O(n2). Sie sind in der Praxis nicht zu empfehlen.

Wie erreichen wir einebessere Komplexit¨at?

Idee(siehe bin¨are Suche):Divide-and-Conquer. Zerlege das Problem rekursivin zwei kleinere Teilprobleme(sortiere die H¨alften des Arrays).

Die resultierenden sortierten H¨alften mischenwir anschließend ineinander.

20

11 17 23 2 7 29 3 13 5 19 11 17 23 2 7 29 3 13 5 19

2 7 11 17 23 3 5 13 19 29

2 3 5 7 11 13 17 19 23 29 Mergesort Mergesort

Mischen

(21)

Mergesort: Pseudo-Code

Bestimmung der Mitte m.

Rekursiver Aufruf von Mergesort f¨ur beide H¨alften, Mischen der beiden H¨alften.

Sortiere das komplette Array mit mergesort(a, 0, n-1).

21

# Subroutine: sortiert Teilbereich

# a[left...right]

function mergesort(a, left, right):

if left >= right: return

m = (left + right) / 2 mergesort(a, left, m) mergesort(a, m+1, right)

Mische die Teilbereiche [left...m]

und [m+1...right] in [left...right]

# sortiere das ganze Feld mergesort(a, 0, n-1)

17 11 23 7 2 29 3 13 5 19 17 11 23 7 2 29 3 13 5 19

2 3 5 7 11 13 17 19 23 29

mergesort

17 11 23 7 2 17 11 23 17 11

11 17 23 11 17 23

mergesort mergesort

2 7 11 17 23 2 7

3 5 13 19 29

mergesort

mergesort

mergesort

Mischen

Mischen

Mischen

Mischen

(22)

Mergesort: Fazit

Zusammenfassung

Die Misch-Operation eines Teilbereichs kostetO(n).

Rekurrenzgleichung: T(n) =2⋅T(n/2) +n.

Komplexit¨at: O(n⋅log n) → Viel, viel besser alsO(n2) (O(n⋅logn)gilt ¨ubrigens auch im Best Case + Average Case).

Fazit

Gutes Allround-Sortierverfahren f¨ur alle F¨alle.

Ben¨otigtExtra Speicher (O(n)) als Puffer bei der Misch-Operation.

22

(23)

Outline

1. Einfache Verfahren: Insertionsort 2. Einfache Verfahren: Selectionsort 3. Einfache Verfahren: Bubblesort 4. Effiziente Verfahren 1: Mergesort 5. Effiziente Verfahren 2: Quicksort

6. Effiziente Verfahren 3: Heapsort

7. Effiziente Verfahren 4: Radix Exchange Sort 8. Stabilit¨at von Sortierverfahren

9. Untere Schranke 10. Externes Sortieren 11. Abschlussbemerkungen

23

(24)

Quicksort

24

(25)

Quicksort

Quicksort(C.A.R. Hoare, 1962)ist in der Praxis h¨aufig das schnellsteunter den popul¨aren Sortierverfahren.

Grundidee

Ebenfalls Divide-and-Conquer(siehe Mergesort).

W¨ahle ein sogenanntesPivot-Element. Bewege alle Werte in die “richtige H¨alfte” (links: <Pivot. Rechts: ≥Pivot).

Sortiere die beiden Teile rekursiv.

25

1117 23 2 7 29 3 13 5 19

5 3 7 2 29 23 17 13 11

2 3 5 7 11 13 17 19 23 29 Quicksort Quicksort

teile Pivot

19

< Pivot  Pivot

(26)

Quicksort: Pseudo-Code (hier: Variante nach Hoare)

Das Pivot ist der Wertganz links.

Subroutine teile(): teilt den Bereich in kleine Werte (links) und große Werte (rechts). Nutzt zwei Zeiger iund j:

isucht von links kommend nach Wertenpivot

jsucht von rechts kommend nach Werten<pivot

Ende sobald beide Zeiger sich treffen.

26

# sortiert Teilbereich a[left...right]

function quicksort(a, left, right):

if left >= right: return

pivot = a[left]

# Teile den Bereich # a[left...right], so dass:

# - a[left...m] < pivot # - a[m+1...right] >= pivot m := teile(a, left, right, pivot) quicksort(a, left, m)

quicksort(a, m+1, right)

# sortiere das ganze Feld quicksort(a, 0, n-1)

# teilt Teilbereich in kleine und große Werte function teile(a, left, right, pivot):

i = left – 1 j = right + 1 while true:

# Suche nächste Positionen:

# - i sucht große Werte in linker Hälfte # - j sucht kleine Werte in rechter Hälfte do i += 1 while i<=right && a[i] < pivot do j -= 1 while j>=left && a[j] > pivot if i>=j:

return j swap a[i] and a[j]

(27)

Quicksort: teile() – Beispiel

27

# teilt Teilbereich in kleine und große Werte function teile(a, left, right, pivot):

i = left – 1 j = right + 1 while true:

# Suche nächste Positionen:

# - i sucht große Werte in linker Hälfte # - j sucht kleine Werte in rechter Hälfte do i += 1 while i<=right && a[i] < pivot do j -= 1 while j>=left && a[j] > pivot if i>=j:

return j swap a[i] and a[j]

11 17 23 2 7 29 3 13 5 19 Pivot-Element = 11

(28)

Quicksort: Komplexit¨ at

Komplexit¨at

Worst Case: O(n2) (Pivot immer gr¨oßtes Element).

Best Case: O(n⋅log(n))(immer Halbierung des Feldes).

Average Case: O(n⋅log(n)) →Im Mittel wirklich “quick”3. Schl¨ussel: Wahl eines “guten” Pivots

zuf¨allig(Monte Carlo – Quicksort)

Median aus erstem, letztem und mittleren Wert3.

Vorteile in der Praxis

Quicksort ist in der Praxis h¨aufig dasschnellste der hier behandelten Verfahren.

Die innere Schleife bestehe aus zwei koh¨arenten Felddurchl¨aufen(gute Lokalit¨atseigenschaften, schnell)

Vergleich gegen einen festen Wert, das Pivot(schnell!)

3R. Sedgewick: Algorithmen in{C, C++, Java}

28

(29)

Quicksort: Fazit (cont’d)

Vorteile in der Praxis

Im Gegensatz zu Mergesort ben¨otigt Quicksort keinen Extra-Speicher (außer dem Call Stack f¨ur die rekursiven Aufrufe, O(n) im Worst Case).

29

(30)

Outline

1. Einfache Verfahren: Insertionsort 2. Einfache Verfahren: Selectionsort 3. Einfache Verfahren: Bubblesort 4. Effiziente Verfahren 1: Mergesort 5. Effiziente Verfahren 2: Quicksort 6. Effiziente Verfahren 3: Heapsort

7. Effiziente Verfahren 4: Radix Exchange Sort 8. Stabilit¨at von Sortierverfahren

9. Untere Schranke 10. Externes Sortieren 11. Abschlussbemerkungen

30

(31)

Heapsort

4

Heapsort, unser letzter vergleichsbasierter Sortieralgorithmus, ...

besitzt eineWorst-Case-Komplexit¨atvon O(n⋅log(n)),

ben¨otigtkeinen zus¨atzlichen Speicher,

basiert auf einer speziellen Datenstruktur, dem Heap.

B¨aume

Heaps sind eine spezielle Art von B¨aumen(sp¨ater mehr).

B¨aume bestehen aus Knoten (= Datenelementen) und Kanten.

Die Knoten sind in Ebenen angeordnet. Auf Ebene 1 befindet sich die Wurzel.

Die H¨ohe(bzw.Tiefe) des Baums entspricht der maximalen Ebene.

4Cormen et al.: Algorithmen – eine Einf¨uhrung. Oldenbourg-Verlag, 2004.

31 Wurzel

Ebene 1 Ebene 2

Ebene 3 Ebene 4

Ebene 5

Höhe = 5

(32)

Exkurs: B¨ aume

x Vater(x)

Kinder(x)

Blätter Kante verboten (Zyklus!)

Binärbaum (kein Knoten Hat mehr als Zwei Kinder)

Alle Knoten (außer der Wurzel) besitzen einenElternknoten (oder Vaterknoten) und sind ihrerseitsKinderdieses Knotens.

Wir unterscheiden zwischen Bl¨attern undinneren Knoten.

Innere Knoten besitzen Kinder, Bl¨atter nicht.

B¨aume enthaltenkeine Zyklen.

In einem bin¨aren Baumhaben Knoten maximal zwei Kinder.

32

(33)

Exkurs: B¨ aume

Vollst¨andigkeit Vollst¨andige B¨aume besitzen nur auf der letzten Ebene Bl¨atter,

Fast vollst¨andige B¨aumeauf den letzten zwei Ebenen.

Die H¨ohe eines vollst¨andigen Baums ist logarithmisch!

Was ist die H¨ohe einesvollst¨andigen bin¨aren Baums mitn Elementen?

Ein Baum der H¨oheh kann n=2h−1 Elemente speichern(Beweis: Induktion).

Gleichung umstellen→h=log2(n+1).

Zentrale Eigenschaft von B¨aumen:

Vollst¨andige B¨aume mit sehr sehr vielen Elementen sind ziemlich flach!

(Bsp. 1,000,000 Elemente→H¨ohe 20).

33 vollständig fast vollständig nicht vollständig,

nicht fast vollständig

Höhe h #Elemente n

1 1

2 3

3 7

4 15

5 31

... ...

10 1023

... ...

h 2h-1

(34)

Heaps

Heapssind eine besondere Form von B¨aumen:

Sie sind bin¨ar(jeder Knoten besitzt ≤2 Kinder).

Sie sind fast vollst¨andig

(die unterste Ebene wird von links aufgef¨ullt!).

Sie erf¨ullen dieHeap-Eigenschaft (gleich mehr).

kein Heap, denn

nicht binär kein Heap, denn

nicht fast vollständig Könnte ein Heap sein

34

(35)

Heaps (cont’d)

Wir stellen uns das zu sortierendeArray a[1], ...,a[n] alsHeap vor!

Element Nr. 1 wird zur Wurzel

Elemente Nr. 2-3 bilden die 1. Ebene

Elemente Nr. 4-7 bilden die 2. Ebene

...

11 17 23 2 7 29 3 13 5 19

1 2 3 4 5 6 7 8 9

11

17 23

2 7 29 3

5

13 19

1

2 3

7 6 5

4

8 9 10

10

Mit folgenden einfachen Funktionen greifen wir auf den Vater/ die Kinder eines Elementes i zu:

parent(i) = ⌊i/2⌋ left child(i) =2⋅i right child(i) =2⋅i+1

35

(36)

Heaps (cont’d)

Heaps sind also bin¨are, fast vollst¨andige B¨aume. Zus¨atzlich erf¨ullen sie noch die folgendeHeap-Eigenschaft (sie sindteilsortiert):

Definition (Heap-Eigenschaft)

Wir interpretieren ein Array a[1], ...,a[n] als bin¨aren Baum. Wir bezeichnen das Array als Min-Heap(bzw.Max-Heap), wenn f¨ur alle i mit1<i ≤n gilt:

a[parent(i)] ≥a[i]

(Max-Heap)

a[parent(i)] ≤a[i]

(Min-Heap)

29

19 23

12 17 18 3

5

3 15

1

2 3

7 6 5 4

8 9 10

3

3 17

5 15 23 19

5

12 18

1

2 3

7 6 5 4

8 9 10

29 19 23 12 17 18 3 3 5 15

1 2 3 4 5 6 7 8 9 10

Max-Heap

Min-Heap

36

(37)

Heapsort: Grundidee

Das zu sortierende Array sei einMax-Heap.

Entnehme in jeder Iteration dieSpitze des Heaps (= das Maximum!) und f¨uge es am Ende des Arrays an.

Stelle f¨ur den Rest des Heaps die Heap-Eigenschaft wieder her.

1 3 22 24 28 46 48 54 73 74 20 10 18 9 7 15 8 6 4 5

Sortierter Teilbereich Heap

Maximum des Heaps

Heap wird kleiner Tausche!

Sortierter Bereich wächst 1 20 22 24 28 46 48 54 73 74 3 10 18 9 7 15 8 6 4 5

Heap kaputt!

Repariere den Heap mit max_heapify()

1 20 22 24 28 46 48 54 73 74 18 10 15 9 7 3 8 6 4 5

37 method heapsort(a):

# turn a into a heap build_max_heap(a) for i = n, n-1, ..., 2:

swap(a[1], a[i])

# decrease the heap by 1 heapsize -= 1

# repair the heap max_heapify(a, 1)

(38)

Heapsort: max heapify(a)

Ausgangssituation: Das Array aist fast ein Heap: Nur an Stelleiist die Heap-Eigenschaft verletzt.

Ansatz: Lasse das “falsche” Element rekursiv an die korrekte Position sinken.

Das Array ist wieder Ein Heap (OK)!

29

4 23

17 15 18 3

5

3 12

1

2 3

7 6 5 4

8 9 10

1 Tausche das Maximum der 3 Werte hoch!

29

17 23

4 15 18 3

5

3 12

1

2 3

7 6 5 4

8 9 10

1

29

17 23

5 15 18 3

4

3 12

1

2 3

7 6 5 4

8 9 10

38

Heap Heap

Heap Heap-Eigenschaft an Stelle i verletzt!

(39)

max heapify(): Komplexit¨ at

Wie teuer ist ein Aufruf vonmax heapify()?

Worst Case: Ein Element sinkt bis nach ganz unten.

Je Ebene: O(1) (3 Werte vergleichen, 2 Werte tauschen).

# Ebenen: H¨ohe des Baums →O(log(n)).

Gesamtaufwand: O(log(n)).

39

Heap

(40)

build max heap()

ZuBeginn verwandeln wir das zu sortierende Array mit build max heap()in einenHeap.

Wir durchlaufen das Array von hinten nach vorne.

An jeder Positioni stellen wir f¨ur den Bereicha[i], ...,a[n] die Heap-Eigenschaft sicher, indem wirmax heapify(a, i) aufrufen.

4 1 3 2 7 9 10 14 8 16

1 2 3 4 5 6 7 8 9 10

i=5 4

1 3

2 7 9 10

8

14 16

1

2 3

7 6 5 4

8 9 10

i=4 4

1 3

2 16 9 10

8

14 7

1

2 3

7 6 5 4

8 9 10

i=3 4

1 3

14 16 9 10

8

2 7

1

2 3

7 6 5 4

8 9 10

Array a

40

method build_max_heap(a):

for i in n/2, ..., 1:

max_heapify(a, i)

(41)

build max heap() (cont’d)

i=2 4

1 10

14 16 9 3

8

2 7

1

2 3

7 6 5 4

8 9 10

i=1 4

16 10

14 7 9 3

8

2 1

1

2 3

7 6 5 4

8 9 10

16

14 10

8 7 9 3

4

2 1

1

2 3

7 6 5 4

8 9 10

Array ist ein Heap (OK)

41

(42)

build max heap()

Was ist die Komplexit¨at vonbuild max heap()?

Ein Aufruf vonmax heapify() kostet O(log(n)).

Wir rufen n/2 (also O(n)) malmax heapify()auf.

Gesamtaufwand: O(n⋅log(n)).

Anmerkung: Man kann sogar zeigen dass der Aufwand O(n)– d.h. noch g¨unstiger – ist5.

5Cormen: Algorithmen -– eine Einf¨uhrung. Oldenbourg-Verlag, 2004.

42

method build_max_heap(a):

for i in n/2, ..., 1:

max_heapify(a, i)

(43)

Heapsort: Diskussion

Aufwandsanalyse

Aufwand f¨urbuild max heap():O(n).

Aufwand pro Schleifendurchlauf:

O(1) +O(1) +O(log(n)) =O(log(n)).

Aufwand der Schleife (n Durchl¨aufe):O(n⋅log(n)).

Gesamtaufwand: O(n) +O(n⋅log(n)) =O(n⋅log(n)). Vergleich mit anderen

effizienten Sortierverfahren

Besserer Worst-Case-Aufwand als Quicksort (O(n2)).

Besserer Speicheraufwand als Mergesort, denn Heapsort ist in-place!

In der Praxis ist Quicksort oft schneller, weil cache-effizienter.

43 method heapsort(a):

# turn a into a heap build_max_heap(a) for i = n, ..., 2:

swap(a[1], a[i]) # decrease the heap heapsize -= 1 # repair the heap max_heapify(a, 1) O(n)

n x O(1) O(1)

O(log n)

(44)

Sortieren: Video

image: [1]

44

(45)

Outline

1. Einfache Verfahren: Insertionsort 2. Einfache Verfahren: Selectionsort 3. Einfache Verfahren: Bubblesort 4. Effiziente Verfahren 1: Mergesort 5. Effiziente Verfahren 2: Quicksort 6. Effiziente Verfahren 3: Heapsort

7. Effiziente Verfahren 4: Radix Exchange Sort

8. Stabilit¨at von Sortierverfahren 9. Untere Schranke

10. Externes Sortieren 11. Abschlussbemerkungen

45

(46)

Digitales Sortieren

Die bisherige Sortierverfahren vergleichen den kompletten Schl¨ussel.

Im folgenden wollen wir die Strukturinformation des Schl¨ussels (d.h. die einzelnen Ziffern)nutzen(“digitales Sortieren”).

Digitales Sortieren: Grundannahmen

Schl¨ussel sind Zeichenketten ¨uber einem Alphabet ausm Elementen (den einzelnen Ziffern).

Wir nennenm auch die Wurzel(Latein: radix).

Wir nehmen an dass die L¨ange der Schl¨ussel (und somit ihr Wertebereich) beschr¨ankt ist.

Radix m Bezeichnung Beispiel

10 Dezimalzahlen 72945

16 Hexadezimalzahlen 48fc

2 Bin¨arzahlen 0011101

256 Strings (extended ASCII) hallo.

46

(47)

Radix Exchange Sort

Voraussetzungen

m-adische Zahlen (hier: Bin¨arzahlen) fester L¨angeK.

Beispiel: 32-Bit-Bin¨arzahlen→232 verschiedene Schl¨ussel.

Ansatz

Wir durchlaufen die einzelnen Ziffern/Bits k =0, ...,K−1 der Schl¨ussel.

F¨ur jede Zifferk parti- tionieren wir rekursiv die Schl¨ussel nach der entspre- chenden Ziffer in 0 (links) und 1 (rechts).

47 function radixsort(a, left, right, k):

for i = left, ..., right:

b[i] = k-tes Bit von Element a[i]

# Teile die Elemente gemäß des k-ten Bits:

# Nullen nach links und Einsen nach rechts.

# -> Schema von Hoare (siehe QuickSort) m = teile (a, b, left, right)

if k >= L:

# letztes Bit erreicht return

else:

# sortiere nach dem nächsten Bit radixsort(a, left, m, k+1) radixsort(a, m+1, right, k+1)

# ganzen Bereich sortieren radixsort(a, 0, n-1, 0)

(48)

Radix Exchange Sort

11 17 23 2 7 29 3 13 5 19

0 1 2 3 4 5 6 7 8

0101110001 10111 00010 00111 1110100011 011010010110011 0101110001 10111 00010 00111 1110100011 011010010110011

00011 00101 00111 00010

00010 00011

01011 00101 01101 00010 00111 00011

00101 00111 01011 01101 2 3 5 7 11 13 17 19 23 29

9

10011 10111 11101 10001

0101100101 10111 00010 00111 1110100011 011011000110011 01011001010110100010 00111 1110100011 10111 1000110011 01011001010110100010 00111 0001111101 10111 1000110011 Bit k=0

00011 00101 00111 00010 01101 01011...

Bit k=1

...

00011 00010 00111 00101 Bit k=2

Bit k=3 00011 00010 00011 00010

Bit k=4 ... ... ... ...

48

(49)

Radix Exchange Sort: Diskussion

Aufwandsbetrachtung

Es sei n die Anzahl der zu sortierenden Schl¨ussel und K die L¨ange der Schl¨ussel.

Jedes Element des Arrays wird genauK-mal besucht (das macht insgesamt K ×n Besuche!).

Jeder Besuch eines Elements kostet O(1).

→ Gesamtkomplexit¨at: O(n⋅K).

Anmerkungen

Achtung:K ist keine Konstante, d.h. Der Aufwand ist abh¨angig vom darstellbaremZahlenbereich!

Sortieren wir z.B.n unterschiedliche Schl¨ussel, muss gelten K ≥logm(n) (also mindestens O(n⋅log(n)).

Radix Exchange Sort ist ung¨unstigbei sehr langen Schl¨ussel / großen Zahlenbereichen. Beispiel: Sortiere 10 64-Bit-Zahlen.

49

(50)

Outline

1. Einfache Verfahren: Insertionsort 2. Einfache Verfahren: Selectionsort 3. Einfache Verfahren: Bubblesort 4. Effiziente Verfahren 1: Mergesort 5. Effiziente Verfahren 2: Quicksort 6. Effiziente Verfahren 3: Heapsort

7. Effiziente Verfahren 4: Radix Exchange Sort 8. Stabilit¨at von Sortierverfahren

9. Untere Schranke 10. Externes Sortieren 11. Abschlussbemerkungen

50

(51)

Stabilit¨ at von Sortierverfahren

Definition (Stabilit¨at)

Wir bezeichnen ein Sortierverfahren alsstabilwenn das Verfahren die Reihenfolgeidentischer Schl¨usselnicht ver¨andert.

Anmerkungen

Relevanz: Objekte nicht unerwartet tauschen.

Beispiel: Sortiert man nach der Note, sollte sich bei gleichen Noten die Reihenfolge der Matrikelnummern nicht ¨andern.

51 Note MatNr

1 1001 2 1002 1 1003 1 1004 1 1005 2 1006

Note MatNr 1 1003 1 1004 1 1001 1 1005 2 1006 2 1002

Note MatNr 1 1001 1 1003 1 1004 1 1005 2 1002 2 1006

OO-Calc, früher nicht

stabil Excel,

stabil

(52)

Beispiel Quicksort

QuickSort istnicht stabil!

Aufruf von teile(): Keine Kontrolle wie Werte links und rechts des Pivots landen.

17 23 2

A

7 29 3 13 2

B

19

Pivot = 11

11 17 23 2

A

7 29 3 13

2

B

19

teile()

11

52

(53)

Outline

1. Einfache Verfahren: Insertionsort 2. Einfache Verfahren: Selectionsort 3. Einfache Verfahren: Bubblesort 4. Effiziente Verfahren 1: Mergesort 5. Effiziente Verfahren 2: Quicksort 6. Effiziente Verfahren 3: Heapsort

7. Effiziente Verfahren 4: Radix Exchange Sort 8. Stabilit¨at von Sortierverfahren

9. Untere Schranke

10. Externes Sortieren 11. Abschlussbemerkungen

53

(54)

Komplexit¨ at Algorithmus ≠ Problem

Wiederholung

Komplexit¨at eines Problems :=

Komplexit¨at desbesten Algorithmus.

Beispiel: Lineare SucheO(n), Bin¨are SucheO(log n).

Worst-Case-Komplexit¨at des Problems “Sortieren?

Sortieren ist maximal O(n⋅log n) (siehe z.B. Mergesort).

Fragestellung: Untere Schranke des Sortierens

Untere Schranke= Worst-Case-Komplexit¨at, die von keinem Verfahren unterschrittenwerden kann.

Eine offensichtliche untere Schranke des Sortierens ist O(n) (wir m¨ussen alle Werte des Arrays besuchen).

Wir zeigen: Auch O(n⋅log(n))ist eine untere Schranke.

54

(55)

Hier: Vergleichsbasierte Verfahren

Wir betrachten hier nurvergleichsbasierte Verfahren, die auf Schl¨usselvergleichen (a[i] <a[j]?) beruhen.

Vergleichsbasiert Selectionsort

Insertionsort Quicksort

Bubblesort Mergesort Heapsort

Nicht Vergleichsbasiert RadixExchangeSort

Countingsort Bucketsort

55

(56)

Untere Schranke O ( n ⋅ log ( n )) : Beweis

Ansatz

Wir k¨onnen nicht alle Sortierverfahren analysieren./.

Stattdessen f¨uhren wir einen Beweis anhand des Entscheidungsbaums von Sortierverfahren.

Beweisidee

Wir erinnern uns:

Ziel von Sortieren ist es, eine passendePermutation π der Eingabedaten zu finden.

Es gibt sehr viele Permutationen.

Ein Sortierverfahren muss also aus sehr vielen m¨oglichen Permutationen diepassendefinden.

Hieraus ergibt sich ein gewisserMindestaufwand.

56

11 17 23 2 7 29 3 13 5 19

0 1 2 3 4 5 6 7 8 9

a (unsortiert)

2 3 5 7 11 13 17 19 23 29

a (sortiert)

0 1 2 3 4 5 6 7 8 9

(57)

Wieviele Permutationen gibt es?

Definition (Permutationen)

Gegeben n Zahlen, lautet die Anzahl m¨oglicher Permutationen n! ∶= 1⋅2⋅3⋅...⋅n

Beweis per vollständiger Induktion (Illustration):

n=1 1 = 1! Permutationen Induktionsanfang

n=2 n=3

2 = 2! Permutationen

3 x 2 = 6 = 3! Permutationen

n → n+1 (n+1) x n! = (n+1)!

Permutationen Induktionsschritt

... ...

Bisher: n! Möglichkeiten

Je Möglichkeit: n+1 neue

...

57

(58)

Entscheidungsb¨ aume

Um die richtige Permutation zu finden, f¨uhrt das Sortierverfahren Vergleiche durch (z.B.a3<a5?).

Wir z¨ahlen zur Berechnung derLaufzeit dieseVergleiche.

Es entsteht ein Entscheidungsbaum.

Beispiel: Sortiere 3 Zahlen

a1<a2 a2<a3

a1<a3

a1<a3

a2<a3

ja

ja

ja ja

ja nein

nein

nein nein nein

a1 a2 a3 a1 a3 a2 a3 a1 a2 a2 a1 a3 a2 a3 a1 a3 a2 a1

Wichtige Beobachtung: Die Anzahl der Bl¨atter entspricht der Anzahl m¨oglicherPermutationen(3!=6).

58

(59)

Beweis untere Schranke

Unterschiedliche Sortierverfahren f¨uhren die Vergleiche in unterschiedlicher Reihenfolge durch (und erzeugen so unterschiedliche Entscheidungsb¨aume).

K¨onnen wir denWorst-Case-Aufwandam Entscheidungsbaumablesen? →Ja: Der

Worst-Case-Aufwand entspricht der Tiefe des Baums!

Wie tief muss der Entscheidungsbaum mindestens sein?

59

(60)

Outline

1. Einfache Verfahren: Insertionsort 2. Einfache Verfahren: Selectionsort 3. Einfache Verfahren: Bubblesort 4. Effiziente Verfahren 1: Mergesort 5. Effiziente Verfahren 2: Quicksort 6. Effiziente Verfahren 3: Heapsort

7. Effiziente Verfahren 4: Radix Exchange Sort 8. Stabilit¨at von Sortierverfahren

9. Untere Schranke 10. Externes Sortieren 11. Abschlussbemerkungen

60

(61)

Motivation: Sehr große Daten sortieren

Bisher: internes Sortieren →das komplette Array befindet sich imHauptspeicher.

Bequemer Zugriffauf alle Elemente in O(1). Externes Sortieren

Die Daten seien nun gr¨oßer als der Hauptspeicher.

Sie befinden sich z.B. in Dateien auf der Festplatte.

Hier erfolgt der Zugriffsequentiell (¨uber I/O-Streams).

Hauptspeicher

O(1)

Datei

... ...

61

(62)

Externes Sortieren

Ansatz

1. Verteile die Daten auf Bl¨ocke

(jeder so groß wie der Hauptspeicher).

2. Sortiere die einzelnen Bl¨ocke intern.

3. Verteile die Bl¨ocke auf mehrere Dateien.

4. Mische die Dateien(vgl. Mergesort).

Mischen vonN Dateien Ahnlich Mergesort:¨

Lese vorderstes Element jeder Eingabedatei →N Werte.

W¨ahle den kleinsten Wert, schreibe ihn in die Ausgabedatei.

Gehe zum n¨achsten Wert.

62 Zerlegen

Sortieren

Mischen

(63)

Externes Sortieren: Beispiel

Wir arbeiten mit 4 Dateien d1,d2,d3,d4.

Hauptspeicher: Gr¨oße 3.

Eingabedaten: in Datei d1. Schritt 1: In Bl¨ocke zerlegen, Bl¨ocke sortieren

Lese Daten blockweise und sortiere Bl¨ocke

Schreibe (sortierte) Bl¨ocke in d3 und d4.

63

17 11 23 2 29 7 3 13 5 19 d1

d2 d3 d4

3 13 5 19 d1

d2 d3 d4

11 17 23 2 7 29

19 d1

d2 d3 d4

11 17 23 2 7 29

3 5 13

1. einlesen, sortieren, schreiben in d3

2. einlesen, sortieren, schreiben in d4

3. einlesen, sortieren, schreiben in d3

4. einlesen, sortieren, schreiben in d4

In d3 und d4 stehen sortierte Blöcke.

(64)

Externes Sortieren: Beispiel

Schritt 2: Mischen

Mische jeDreier-Bl¨ocke ausd3 und d4.

Wir erhalten sortierte Bl¨ocke der Gr¨oße 6.

Schreibe diese abwechselnd in d1 und d2.

Wenn wir dieses Mischen wiederholen, erhalten wir sortierte 12er-Bl¨ocke, 24er-Bl¨ocke, ...

Wir mischen bis die kompletten Daten sortiert sind.

64

19 3 5 13 d1

d2 d3 d4

11 17 23

2 7 29

19 d1

d2 d3 d4

3 5 13 11 17 23

2 7 29

Sechser- Blöcke 19

d1 d2 d3 d4

11 17 23 2 7 29

3 5 13

Dreier- Blöcke

d3 2 3 5 7 111317192329

4. d3 noch nach d1 kopieren!

1. Mische diese Blöcke in d1

1. Mische diese Blöcke in d2

3. Mische diese Blöcke in d3

(65)

N-Wege-Mischen

Im Beispiel wurde ein sogenanntesZwei-Wege-Mischen durchgef¨uhrt:

Jeder Mischvorgang liest aus zweiDateien (z.B. d1,d2).

Jeder Mischvorgang schreibt in zweiDateien (z.B. d3,d4). Verallgemeinerung:N-Wege-Mischen

Mische ausN Dateien inN Dateien (N Quellen, N Senken).

Je gr¨oßer N, destoschneller wachsen die Bl¨ocke und desto weniger Mischvorg¨ange werden ben¨otigt.

N ist in der Praxisbeschr¨ankt:

Es gibt eine Obergrenze parallel lesbarer Dateien(z.B. Linux:

“ulimit -n”).

65

d1 d2 dN ...

dN+1 dN+2 d2N ...

(66)

N-Wege-Mischen: Analyse

Gegebene Parameter

Parameter Definition

Anzahl zu sortierender Werte n Kapazit¨at des Hauptspeichers H

Anzahl Dateien 2N

Anzahl Bl¨ocke B := n / H

Wir berechnen die Laufzeit

Anzahl der Mischvorg¨ange:logN(B) =logN(n/H).

Beispiel: 1 Mrd. Objekte der Gr¨oße 1KB (= 1TB), 1 GB Hauptspeicher

Objekte im Hauptspeicher: H = 1 Mio.

Anzahl Bl¨ocke: B = 1 Mrd. / 1 Mio. = 1000.

Anzahl Mischvorg¨ange: N=10log10(1000) =3.

66

(67)

Outline

1. Einfache Verfahren: Insertionsort 2. Einfache Verfahren: Selectionsort 3. Einfache Verfahren: Bubblesort 4. Effiziente Verfahren 1: Mergesort 5. Effiziente Verfahren 2: Quicksort 6. Effiziente Verfahren 3: Heapsort

7. Effiziente Verfahren 4: Radix Exchange Sort 8. Stabilit¨at von Sortierverfahren

9. Untere Schranke 10. Externes Sortieren 11. Abschlussbemerkungen

67

(68)

Benchmark Sortierverfahren

Einfache vs. schnelle Sortierverfahren in der Praxis:

68

(69)

Sortierverfahren in Java

In der Bibliothekjava.util bietet die KlasseArrays Sortierverfahren als statische Methoden, z.B.sort(int[] a).

Implementierung?

F¨urshort, int, long:

“Dual-Pivot” QuickSort.

F¨urObjekte:

MergeSort (stabil).

Hybride Verfahren

In der Praxis werden h¨aufig Kombinationen mehrerer Verfahren verwendet.

Merge-Insertion-Sort [3]

Introsort [2] (Quick-/Merge)

...

69

(70)

References I

[1] 15 Sorting Algorithms in 6 Minutes.

https://www.youtube.com/watch?v=kPRA0W1kECg(retrieved: May 2019).

[2] Introsort (Wikipedia).

https://en.wikipedia.org/wiki/Introsort(retrieved: May 2019).

[3] Merge-Insertionsort (Wikipedia).

https://en.wikipedia.org/wiki/Merge-insertion_sort(retrieved: May 2019).

[4] Colin Scott.

Latency Numbers Every Programmer Should Know.

https://people.eecs.berkeley.edu/~rcs/research/interactive_latency.html(retrieved: Mar 2018).

70

Referenzen

ÄHNLICHE DOKUMENTE

When this value occurs as the contents of a character position in a sort key, it is sorted according to the position the value occupies in the user

In addition to the FILE control statement required by CYBER Record Manager, you must also supply a FILE directive to specify all of the input and output files

Z = (12,5,11,6, 13,9, 20,3, 1,19,8) Sortieren Sie die Zahlen auf einem Blatt mit dem. a) rekursiven Merge-Sort Algorithmus und dem b) iterativen

Upon notification by customer to the nearest DIGITAL office that the computer system, including all required prerequisite hardware and software, is ready for the

Upon notification by customer to the nearest DIGITAL office that the computer system, including all required prerequisite hardware and software, is ready for the

(If the user specified an output_file exit procedure, then the status code data_seq_error is returned to that exit procedure; see the sort_$return entry below.)

I Insertionsort betrachtet die Elemente von vorne nach hinten und sortiert sie in den bereits sortierten Bereich am.

I In der Analyse von Mergesort werden wir eine Logarithmusfunktion verwendet. I Dies ist bei der Analyse von Laufzeiten oft