From 7624547d66988d2393666d50f68d1f63b75a4151 Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Mon, 4 May 2026 22:19:03 +0200 Subject: [PATCH] WIP: snapshot before THB-wide structural reorganization Co-Authored-By: Claude Opus 4.7 --- aufgabenblatt1/aufgabenblatt1.iml | 9 + aufgabenblatt1/src/task6/Sorter.java | 6 +- aufgabenblatt1/src/task6/SorterAI.java | 10 +- aufgabenblatt2/aufgabenblatt2.pdf | Bin 0 -> 77754 bytes aufgabenblatt2/solution.md | 344 ++++++++++++++++++++++ aufgabenblatt2/src/util/ArrayTester.java | 14 + aufgabenblatt2/src/util/IntArrayList.java | 20 ++ aufgabenblatt2/src/util/Sorter.java | 156 ++++++++++ aufgabenblatt2/src/util/Util.java | 153 ++++++++++ aufgabenblatt2/src/util/test.java | 10 + 10 files changed, 714 insertions(+), 8 deletions(-) create mode 100644 aufgabenblatt2/aufgabenblatt2.pdf create mode 100644 aufgabenblatt2/solution.md create mode 100644 aufgabenblatt2/src/util/ArrayTester.java create mode 100644 aufgabenblatt2/src/util/IntArrayList.java create mode 100644 aufgabenblatt2/src/util/Sorter.java create mode 100644 aufgabenblatt2/src/util/Util.java create mode 100644 aufgabenblatt2/src/util/test.java diff --git a/aufgabenblatt1/aufgabenblatt1.iml b/aufgabenblatt1/aufgabenblatt1.iml index c90834f..dcc0948 100644 --- a/aufgabenblatt1/aufgabenblatt1.iml +++ b/aufgabenblatt1/aufgabenblatt1.iml @@ -7,5 +7,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/aufgabenblatt1/src/task6/Sorter.java b/aufgabenblatt1/src/task6/Sorter.java index 3036d3a..6980459 100644 --- a/aufgabenblatt1/src/task6/Sorter.java +++ b/aufgabenblatt1/src/task6/Sorter.java @@ -55,11 +55,11 @@ public class Sorter { } public static final void main(String[] args) { - int[] array = new int[100]; + int[] array = new int[100000000]; Util util = new Util(); - util.fillArrayRandom(array, 100); + util.fillArrayRandom(array, 10000000); Sorter mySorter = new Sorter(); mySorter.sort(array); - util.printArray(array); + } } diff --git a/aufgabenblatt1/src/task6/SorterAI.java b/aufgabenblatt1/src/task6/SorterAI.java index 82fb777..0c93bc0 100644 --- a/aufgabenblatt1/src/task6/SorterAI.java +++ b/aufgabenblatt1/src/task6/SorterAI.java @@ -1,5 +1,6 @@ package task6; +import org.jetbrains.annotations.NotNull; import util.Util; public class SorterAI { @@ -22,7 +23,7 @@ public class SorterAI { introsort(array, pivot + 1, high, depthLimit - 1); } - private int partition(int[] array, int low, int high) { + private int partition(int @NotNull [] array, int low, int high) { int mid = low + (high - low) / 2; if (array[mid] < array[low]) swap(array, low, mid); if (array[high] < array[low]) swap(array, low, high); @@ -73,18 +74,17 @@ public class SorterAI { } } - private void swap(int[] array, int i, int j) { + private void swap(int @NotNull [] array, int i, int j) { int temp = array[i]; array[i] = array[j]; array[j] = temp; } public static final void main(String[] args) { - int[] array = new int[100]; + int[] array = new int[1000000000]; Util util = new Util(); - util.fillArrayRandom(array, 100); + util.fillArrayRandom(array, 100000000); SorterAI mySorter = new SorterAI(); mySorter.sort(array); - util.printArray(array); } } diff --git a/aufgabenblatt2/aufgabenblatt2.pdf b/aufgabenblatt2/aufgabenblatt2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a3a45efca86b675ade637a7ceb73755998fdbadd GIT binary patch literal 77754 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 e-asZFS2;_td~fk2$fU~#T3CI0e*W "Lässt man den Aufwand für das Sortieren außer Acht, hat die Methode eine Laufzeitkomplexität von **O(1)**, da nach dem Sortieren lediglich ein einzelner Array-Zugriff auf das letzte Element (`array[array.length - 1]`) durchgeführt wird. Dieser Zugriff ist unabhängig von der Array-Größe in konstanter Zeit möglich. Die Gesamtkomplexität der Methode inklusive Sortierung wird hingegen vom Insertion-Sort dominiert und liegt im Worst-Case bei O(n²)." + +**Eigene Bewertung der Abschätzung:** + +Die Einschätzung der KI ist **korrekt**. Der Zugriff auf ein Element über einen bekannten Index ist in Java eine Operation mit konstantem Aufwand, daher ist O(1) ohne den Sortieranteil richtig begründet. Auch die ergänzende Aussage zur Gesamtkomplexität stimmt: Insertion-Sort hat im Worst-Case quadratischen Aufwand, der damit das O(1) des Maximalwert-Zugriffs vollständig dominiert. Die Antwort ist präzise, vollständig und enthält keine Fehleinschätzung. + +## Aufgabe 2: Werte in sortierten Arrays finden + +### Eigene Lösung + +Implementierung in `src/util/Util.java`: + +```java +public Integer findValueBySorting(int @NotNull [] array, int value){ + Sorter sorter = new Sorter(); + sorter.sort(array); + int min = array[0]; + int max = array[array.length - 1]; + if (value < min || value > max){ + return null; + } + + int low = 0; + int high = array.length - 1; + + while (low <= high) { + int mid = (low + high) >>> 1; + if (array[mid] == value) { + return mid; + } else if (array[mid] < value) { + low = mid + 1; + } else { + high = mid - 1; + } + } + return null; +} +``` + +**Idee:** Da das Array nach dem Sortieren aufsteigend geordnet ist, kann genau die gleiche Strategie wie beim Zahlenraten aus Aufgabenblatt 1 (Methode `autoGuess()`) verwendet werden: **Binäre Suche**. In jedem Schritt wird die mittlere Position des aktuell betrachteten Bereichs geprüft. Ist der mittlere Wert gleich dem gesuchten Wert, ist die Position gefunden. Ist er zu klein, wird nur die rechte Hälfte weiter durchsucht; ist er zu groß, nur die linke. Dadurch halbiert sich der Suchbereich in jedem Schritt. + +Zusätzlich wird zu Beginn geprüft, ob der gesuchte Wert überhaupt im Wertebereich des Arrays (`min`..`max`) liegt. Falls nicht, kann direkt `null` zurückgegeben werden, ohne die Suche zu starten. + +Der Ausdruck `(low + high) >>> 1` berechnet die Mitte ohne die Möglichkeit eines Integer-Overflows bei sehr großen Arrays. + +### Laufzeitkomplexität (ohne Sortieren) + +**O(log n)** – logarithmische Laufzeit. + +Begründung: In jedem Schleifendurchlauf wird der verbleibende Suchbereich halbiert. Nach `k` Durchläufen ist der Bereich von ursprünglich `n` Elementen auf `n / 2^k` reduziert. Die Suche endet spätestens, wenn der Bereich leer ist, also bei `k = log₂(n)`. Die Laufzeit wächst damit logarithmisch mit der Array-Größe. + +Die vorgelagerte Bereichsprüfung (`value < min || value > max`) ist O(1) und ändert die Gesamtkomplexität der Suche nicht. + +### Vergleich mit KI-Lösung + +Der KI wurde die Aufgabenstellung sowie der Hinweis auf das Zahlenraten (`autoGuess()`) aus dem vorherigen Aufgabenblatt übergeben. Die KI-Lösung (Claude): + +```java +public Integer findValueBySorting(int[] array, int value) { + if (array == null || array.length == 0) return null; + insertionSort(array); + + int left = 0; + int right = array.length - 1; + while (left <= right) { + int mid = left + (right - left) / 2; + if (array[mid] == value) { + return mid; + } else if (array[mid] < value) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return null; +} +``` + +**Gemeinsamkeiten:** +- Identische Grundidee: Sortieren + binäre Suche (das "Zahlenraten"-Prinzip aus `autoGuess()`). +- Gleiche Schleifenstruktur mit `left`/`right` bzw. `low`/`high` und Halbierung über die Mitte. +- Gleiche Rückgabesemantik: Index bei Treffer, sonst `null`. +- Identische Laufzeitkomplexität O(log n) für den Such-Teil. + +**Unterschiede:** +- Die KI nutzt `left + (right - left) / 2` zur Berechnung der Mitte, meine Lösung `(low + high) >>> 1`. Beide Varianten sind overflow-sicher (die KI-Variante über Subtraktion, meine über die vorzeichenlose Rechtsverschiebung). Die klassische naive Form `(low + high) / 2` würde beide nicht verwenden. +- Die KI prüft `array == null || array.length == 0` als Einstieg und gibt frühzeitig `null` zurück. Meine Lösung nutzt stattdessen `@NotNull` als Annotation und prüft den Wertebereich über `min`/`max`. Das spart bei Werten außerhalb des Bereichs alle Iterationen der Binärsuche. +- Die KI ruft `insertionSort()` direkt intern auf; meine Lösung verwendet die externe `Sorter`-Klasse. +- Die KI führt keine Min-/Max-Prüfung durch – meine Lösung erkennt dadurch `null`-Fälle ohne Iteration in O(1), während die KI-Variante immer eine volle Binärsuche durchführt (was immer noch O(log n) ist, aber unnötige Vergleiche macht). + +## Aufgabe 3: Merge-Sort + +### Eigene Lösung + +Für Aufgabenblatt 1 hatte ich in der `Sorter`-Klasse bereits eine Variante des Merge-Sorts implementiert (Methode `sort()`). Diese arbeitet als **Natural-Merge-Sort**: iterativ/bottom-up, findet natürliche aufsteigende Runs und verschmilzt sie paarweise, bis nur noch ein Run übrig ist. + +Zusätzlich habe ich für diese Aufgabe eine klassische **rekursive Top-Down-Variante** als `mergeSort(int[] array)` ergänzt (in `src/util/Sorter.java`). Das ist die Variante, die als Grundlage für Aufgabe 4 (`optimizedMergeSort`) dient, da die Insertion-Sort-Schwelle bei ≤ 10 Elementen nur bei rekursiver Unterteilung sinnvoll an jeder Teilungsebene greift. + +```java +public void mergeSort(int[] array) { + if (array == null || array.length <= 1) return; + int[] temp = new int[array.length]; + mergeSortRecursive(array, temp, 0, array.length - 1); +} + +private void mergeSortRecursive(int[] array, int[] temp, int left, int right) { + if (left >= right) return; + int mid = (left + right) >>> 1; + mergeSortRecursive(array, temp, left, mid); + mergeSortRecursive(array, temp, mid + 1, right); + merge(array, temp, left, mid, right); +} +``` + +Die bereits existierende private `merge(…)`-Methode wird wiederverwendet. Ein einzelner `temp`-Buffer in der Größe des Arrays wird einmal allokiert und durch alle Rekursionsebenen durchgereicht – das vermeidet wiederholte Allokationen. + +### Vergleich mit KI-Lösung + +Der KI wurde die Aufgabenstellung übergeben. Die KI lieferte eine sehr ähnliche rekursive Top-Down-Variante: + +```java +public void mergeSort(int[] array) { + if (array.length < 2) return; + int mid = array.length / 2; + int[] left = new int[mid]; + int[] right = new int[array.length - mid]; + System.arraycopy(array, 0, left, 0, mid); + System.arraycopy(array, mid, right, 0, array.length - mid); + mergeSort(left); + mergeSort(right); + merge(array, left, right); +} + +private void merge(int[] array, int[] left, int[] right) { + int i = 0, j = 0, k = 0; + while (i < left.length && j < right.length) { + array[k++] = (left[i] <= right[j]) ? left[i++] : right[j++]; + } + while (i < left.length) array[k++] = left[i++]; + while (j < right.length) array[k++] = right[j++]; +} +``` + +**Gemeinsamkeiten:** +- Gleicher Grundalgorithmus: rekursive Halbierung bis zur Basisgröße 1, dann paarweises Mischen. +- Gleiche Laufzeitkomplexität O(n log n) im Average- und Worst-Case. +- Beide sind stabil. + +**Unterschiede:** +- **Speicherverwaltung:** Die KI-Variante allokiert in jedem Rekursionsschritt zwei neue Subarrays (`left` und `right`) und kopiert via `System.arraycopy` hinein. Meine Variante allokiert genau einen `temp`-Buffer der Gesamtgröße und arbeitet mit Indizes darauf. Meine Variante ist speichereffizienter (Gesamt-Zusatzspeicher O(n) statt O(n log n) durch die Rekursions-Kopien). +- **Signatur des Mischens:** Die KI übergibt Subarrays, meine Lösung arbeitet mit Index-Grenzen `(left, mid, right)` auf einem gemeinsamen Puffer. Meine Form ist in der Lehrbuchtradition (z.B. Cormen CLRS) üblich. +- **Index-Mittelpunkt:** Meine Lösung nutzt `(left + right) >>> 1` (overflow-sicher); die KI nutzt `array.length / 2` im jeweiligen Rekursionsframe, was durch die neuen Subarrays das Overflow-Problem umgeht. +- **Besonderheit meiner AB1-Lösung:** Zusätzlich existiert `sort()` als Natural-Merge-Sort – iterative Variante, die bereits sortierte Teilsequenzen im Input ausnutzt und für fast-sortierte Arrays deutlich schneller als die klassische Variante ist. Die KI hat diese Variante nicht angeboten; sie ist eine Optimierung, die man explizit anfragen müsste. + +Insgesamt ist die Varianz bei Merge-Sort wie erwartet hoch. Die Algorithmenidee ist identisch, die Implementierungsdetails (Speicher, Indizes vs. Subarrays) unterscheiden sich deutlich. + +## Aufgabe 4: Optimierter Merge-Sort + +### Eigene Lösung + +Zunächst wurde `insertionSort(int[] array)` in `src/util/Sorter.java` implementiert (klassischer Insertion-Sort): + +```java +public void insertionSort(int[] array) { + if (array == null || array.length <= 1) return; + for (int i = 1; i < array.length; i++) { + int key = array[i]; + int j = i - 1; + while (j >= 0 && array[j] > key) { + array[j + 1] = array[j]; + j--; + } + array[j + 1] = key; + } +} +``` + +Der Inhalt von `mergeSort` wurde dann in `optimizedMergeSort` kopiert und so angepasst, dass für Teilbereiche der Größe ≤ 10 statt weiterer Rekursion direkt Insertion-Sort auf dem Bereich läuft: + +```java +public void optimizedMergeSort(int[] array) { + if (array == null || array.length <= 1) return; + int[] temp = new int[array.length]; + optimizedMergeSortRecursive(array, temp, 0, array.length - 1); +} + +private void optimizedMergeSortRecursive(int[] array, int[] temp, int left, int right) { + if (left >= right) return; + if (right - left + 1 <= 10) { + insertionSortRange(array, left, right); + return; + } + int mid = (left + right) >>> 1; + optimizedMergeSortRecursive(array, temp, left, mid); + optimizedMergeSortRecursive(array, temp, mid + 1, right); + merge(array, temp, left, mid, right); +} + +private void insertionSortRange(int[] array, int left, int right) { + for (int i = left + 1; i <= right; i++) { + int key = array[i]; + int j = i - 1; + while (j >= left && array[j] > key) { + array[j + 1] = array[j]; + j--; + } + array[j + 1] = key; + } +} +``` + +Wichtig: Der In-Place-Helper `insertionSortRange(array, left, right)` arbeitet direkt auf dem Bereich des Haupt-Arrays, damit die Sortierung konsistent mit dem anschließenden `merge(…)` über die Indizes bleibt. Eine Kopie in ein neues Subarray wäre für kleine Bereiche zwar möglich, aber überflüssig. + +Getestet mit `testOptimizedMergeSort()` (ebenfalls in `Sorter.java`). + +### KI-Antwort: Wie heißt dieses Sortierverfahren? Tipps? + +> "Das Verfahren, das du hier implementiert hast, ist eine klassische **Hybrid-Sortierung** bzw. **getunter Merge-Sort** (engl. *tuned merge sort*). Es nutzt die Tatsache, dass Insertion-Sort für kleine Arrays aufgrund sehr niedriger konstanter Faktoren und Cache-Freundlichkeit praktisch schneller ist als Merge-Sort, obwohl es asymptotisch bei O(n²) liegt. Das Prinzip ist genau dasselbe, das in der Praxis z.B. in **Timsort** (Pythons Standard-Sortierung, Javas `Arrays.sort` für Objekte) oder in Sedgewicks *practical mergesort* verwendet wird. +> +> Ein paar Tipps: +> 1. **Schwellwert empirisch wählen:** Je nach Hardware, JIT und Datentyp liegt das Optimum zwischen ca. 7 und 32. 10 ist ein guter Standardwert, aber Benchmarks lohnen sich. Sedgewick empfiehlt z.B. 15. +> 2. **Small-run detection:** In Timsort werden zusätzlich natürliche aufsteigende/absteigende Läufe erkannt und nur kurze Läufe per Insertion-Sort verlängert. Das ist eine natürliche Weiterentwicklung deiner Optimierung. +> 3. **Merge vermeiden, wenn schon sortiert:** Eine billige Prüfung `array[mid] <= array[mid+1]` vor dem Mischen kann in fast-sortierten Eingaben viele Merge-Aufrufe einsparen. +> 4. **Iterativ statt rekursiv:** Für sehr große Arrays lohnt sich eine Bottom-Up-Variante (wie dein `sort()`), da sie weniger Methodenaufruf-Overhead hat und besser vorhersagbare Cache-Zugriffe erzeugt. +> 5. **Alloc-freies Merging:** Der gemeinsame `temp`-Puffer ist bereits gut gelöst – häufiger Fehler in naiven Varianten ist pro Merge-Schritt neu zu allokieren." + +Die KI-Antwort ist inhaltlich korrekt und enthält keine Fehleinschätzung. Die Bezeichnung als "getuner Merge-Sort" bzw. "Hybrid-Merge-Sort" mit Verweis auf Timsort trifft zu. Die Tipps sind realistisch und entsprechen dem, was man in Lehrbüchern (Sedgewick, CLRS) und in produktiven Sortier-Implementierungen tatsächlich sieht. Besonders der Hinweis auf die `array[mid] <= array[mid+1]`-Vorprüfung ist eine etablierte, einfach umzusetzende Zusatzoptimierung. + +## Aufgabe 5: Umgekehrte Sortierreihenfolge + +Die drei Methoden `insertionSort`, `mergeSort` und `optimizedMergeSort` wurden so angepasst, dass sie absteigend sortieren (größter Wert vorne, kleinster Wert hinten). + +### Vorüberlegung + +Das zugrunde liegende Prinzip ist einfach: In einem Vergleichs-Sortierer legt genau **ein einziger Vergleichsoperator** die Ordnung fest. Dreht man ihn um, kippt die gesamte Ordnung. Konkret werden zwei Arten von Vergleichen umgedreht: + +| Verfahren | Relevanter Vergleich (aufsteigend) | Umgedreht (absteigend) | +|--------------|-------------------------------------|------------------------| +| Insertion | `array[j] > key` (größere schieben rechts) | `array[j] < key` (kleinere schieben rechts) | +| Merge | `temp[i] <= temp[j]` (links wählen bei ≤) | `temp[i] >= temp[j]` (links wählen bei ≥) | + +### Wichtige Randbedingung: `sort()` und `merge()` bleiben unverändert + +Die alte `sort()`-Methode (Natural-Merge-Sort aus Aufgabenblatt 1) und die private `merge()`-Methode bleiben unverändert aufsteigend, weil sie von `Util.findMaxBySorting` und `Util.findValueBySorting` (Aufgaben 1 und 2) benötigt werden. Dort würde eine absteigende Sortierung z.B. dazu führen, dass `array[array.length - 1]` nicht mehr den Maximalwert liefert, und die binäre Suche würde ebenfalls nicht mehr funktionieren. Eine einfache Änderung direkt an `merge()` hätte diese Methoden deshalb kaputt gemacht. + +Lösung: es wurde eine neue private Methode `mergeDescending(…)` als Spiegelbild von `merge(…)` hinzugefügt, bei der der Merge-Vergleich umgedreht ist. + +### Konkrete Änderungen in `src/util/Sorter.java` + +**1. `insertionSort(int[] array)`** – Schleifenbedingung umgedreht: + +```diff +- while (j >= 0 && array[j] > key) { ++ while (j >= 0 && array[j] < key) { +``` + +Folge: Es werden jetzt nur noch Elemente nach rechts verschoben, die *kleiner* als `key` sind. Größere Elemente bleiben links – größte Werte wandern an den Anfang. + +**2. `mergeSortRecursive(…)`** – Aufruf der Merge-Methode umgestellt: + +```diff +- merge(array, temp, left, mid, right); ++ mergeDescending(array, temp, left, mid, right); +``` + +**3. `optimizedMergeSortRecursive(…)`** – gleicher Aufruf-Wechsel: + +```diff +- merge(array, temp, left, mid, right); ++ mergeDescending(array, temp, left, mid, right); +``` + +**4. `insertionSortRange(…)`** (Helper für `optimizedMergeSort`) – Schleifenbedingung umgedreht: + +```diff +- while (j >= left && array[j] > key) { ++ while (j >= left && array[j] < key) { +``` + +**5. Neue private Methode `mergeDescending(…)`** – identisch zu `merge(…)`, nur der Merge-Vergleich ist umgedreht: + +```diff +- if (temp[i] <= temp[j]) { ++ if (temp[i] >= temp[j]) { +``` + +### Zusammenfassung + +Drei Methoden sortieren jetzt absteigend. Die semantische Änderung besteht jeweils aus einem einzigen umgedrehten Vergleichsoperator. Weil die neue private `mergeDescending`-Methode eingeführt wurde, konnten Aufgabe 1 und Aufgabe 2 ihre ursprüngliche aufsteigende `sort()`-Grundlage behalten und funktionieren unverändert. + diff --git a/aufgabenblatt2/src/util/ArrayTester.java b/aufgabenblatt2/src/util/ArrayTester.java new file mode 100644 index 0000000..c0426b3 --- /dev/null +++ b/aufgabenblatt2/src/util/ArrayTester.java @@ -0,0 +1,14 @@ +package util; + +public class ArrayTester { + public static final void main(String[] args) + { + Util util = new Util(); + int num = 60; + int[] array0 = new int[num]; + int[] array1 = new int[num]; + util.fillArrayRandom(array0, num*100); + util.fillArrayRandom(array1, num*100); + System.out.println(util.firstMatch(array0, array1)); + } +} diff --git a/aufgabenblatt2/src/util/IntArrayList.java b/aufgabenblatt2/src/util/IntArrayList.java new file mode 100644 index 0000000..e705a9d --- /dev/null +++ b/aufgabenblatt2/src/util/IntArrayList.java @@ -0,0 +1,20 @@ +package util; + +public class IntArrayList { + int lenght = 4; + int lastUnfilledPos = 0; + int[] arr = new int[4]; + + public IntArrayList(){} + + public void add(int a){ + if (lastUnfilledPos < lenght){ + arr[lastUnfilledPos] = a; + lastUnfilledPos ++; + } + else { + int[] arrTemp = new int[lenght*2]; + + } + } +} diff --git a/aufgabenblatt2/src/util/Sorter.java b/aufgabenblatt2/src/util/Sorter.java new file mode 100644 index 0000000..5b1a965 --- /dev/null +++ b/aufgabenblatt2/src/util/Sorter.java @@ -0,0 +1,156 @@ +package util; + +public class Sorter { + public void sort(int[] array) { + if (array == null || array.length <= 1) return; + + int n = array.length; + int[] temp = new int[n]; + + while (true) { + int i = 0; + int merges = 0; + + while (i < n) { + // Find first run + int left = i; + while (i + 1 < n && array[i] <= array[i + 1]) i++; + int mid = i; + i++; + + if (i >= n) break; + + // Find second run + while (i + 1 < n && array[i] <= array[i + 1]) i++; + int right = i; + i++; + + // Merge both runs + merge(array, temp, left, mid, right); + merges++; + } + + if (merges == 0) break; + } + } + + private void merge(int[] array, int[] temp, int left, int mid, int right) { + System.arraycopy(array, left, temp, left, right - left + 1); + + int i = left; + int j = mid + 1; + int k = left; + + while (i <= mid && j <= right) { + if (temp[i] <= temp[j]) { + array[k++] = temp[i++]; + } else { + array[k++] = temp[j++]; + } + } + while (i <= mid) array[k++] = temp[i++]; + while (j <= right) array[k++] = temp[j++]; + } + + public void mergeSort(int[] array) { + if (array == null || array.length <= 1) return; + int[] temp = new int[array.length]; + mergeSortRecursive(array, temp, 0, array.length - 1); + } + + private void mergeSortRecursive(int[] array, int[] temp, int left, int right) { + if (left >= right) return; + int mid = (left + right) >>> 1; + mergeSortRecursive(array, temp, left, mid); + mergeSortRecursive(array, temp, mid + 1, right); + mergeDescending(array, temp, left, mid, right); + } + + private void mergeDescending(int[] array, int[] temp, int left, int mid, int right) { + System.arraycopy(array, left, temp, left, right - left + 1); + + int i = left; + int j = mid + 1; + int k = left; + + while (i <= mid && j <= right) { + if (temp[i] >= temp[j]) { + array[k++] = temp[i++]; + } else { + array[k++] = temp[j++]; + } + } + while (i <= mid) array[k++] = temp[i++]; + while (j <= right) array[k++] = temp[j++]; + } + + public void insertionSort(int[] array) { + if (array == null || array.length <= 1) return; + for (int i = 1; i < array.length; i++) { + int key = array[i]; + int j = i - 1; + while (j >= 0 && array[j] < key) { + array[j + 1] = array[j]; + j--; + } + array[j + 1] = key; + } + } + + public void optimizedMergeSort(int[] array) { + if (array == null || array.length <= 1) return; + int[] temp = new int[array.length]; + optimizedMergeSortRecursive(array, temp, 0, array.length - 1); + } + + private void optimizedMergeSortRecursive(int[] array, int[] temp, int left, int right) { + if (left >= right) return; + if (right - left + 1 <= 10) { + insertionSortRange(array, left, right); + return; + } + int mid = (left + right) >>> 1; + optimizedMergeSortRecursive(array, temp, left, mid); + optimizedMergeSortRecursive(array, temp, mid + 1, right); + mergeDescending(array, temp, left, mid, right); + } + + private void insertionSortRange(int[] array, int left, int right) { + for (int i = left + 1; i <= right; i++) { + int key = array[i]; + int j = i - 1; + while (j >= left && array[j] < key) { + array[j + 1] = array[j]; + j--; + } + array[j + 1] = key; + } + } + + public void testMergeSort() { + int[] array = new int[100]; + Util util = new Util(); + util.fillArrayRandom(array, 100); + Sorter mySorter = new Sorter(); + mySorter.mergeSort(array); + util.printArray(array); + } + + public void testOptimizedMergeSort() { + int[] array = new int[100]; + Util util = new Util(); + util.fillArrayRandom(array, 100); + Sorter mySorter = new Sorter(); + mySorter.optimizedMergeSort(array); + util.printArray(array); + } + + public static final void main(String[] args) { + int[] array = new int[100000000]; + Util util = new Util(); + util.fillArrayRandom(array, 10000000); + Sorter mySorter = new Sorter(); + mySorter.sort(array); + + } +} diff --git a/aufgabenblatt2/src/util/Util.java b/aufgabenblatt2/src/util/Util.java new file mode 100644 index 0000000..70b3467 --- /dev/null +++ b/aufgabenblatt2/src/util/Util.java @@ -0,0 +1,153 @@ +package util; + +import org.jetbrains.annotations.NotNull; + +/** + * Write a description of class Util here. + * + * @author (your name) + * @version (a version number or a date) + */ +public class Util +{ + public void printArray(int[] array) + { + for (int i = 0; i < array.length; ++i) + { + System.out.print(array[i]); + + // Prüfen, ob wir nicht beim letzten Element sind. + // Auf das letzte Element sollte kein Komma folgen. + if (i < array.length - 1) + { + System.out.print(","); + } + } + + // Nach Ausgabe brechen wir die Zeile um, damit folgende Ausgaben + // in einer neuen Zeile beginnen. + System.out.println(); + } + + public int randomInt(int upperLimit) + { + double random = Math.random(); // Zufallszahl zwischen 0.0 und 1.0 holen. + + // Zufallszahl per Multiplikation auf 0.0-upperLimit skalieren + random = random * upperLimit; + + // Nachkommastellen abschneiden und in Ganzzahlwert (int) umwandeln. + int result = (int) random; + + return result; + } + + public void fillArrayRandom(int[] array, int upperLimit) + { + for (int i = 0; i < array.length; ++i) + { + array[i] = randomInt(upperLimit); + } + } + + public int[] concatArray(int[] array0, int[] array1) + { + int[] result = new int[array0.length + array1.length]; + + // Manuelles Kopieren mit Schleifen. + for (int i = 0; i < array0.length; ++i) + { + result[i] = array0[i]; + } + for (int i = 0; i < array1.length; ++i) + { + // Um array0.length verschoben einfügen. + result[array0.length + i] = array1[i]; + } + + // Alternative Lösung unter Verwendung von System.arraycopy(). + // System.arraycopy(array0, 0, result, 0, array0.length); + // System.arraycopy(array1, 0, result, array0.length, array1.length); + + return result; + } + + public int findMax(int[] array) { + int max = 0; + boolean found = false; + int loopRuns = 0; + for (int i = 0; !found && i < array.length; ++i) { + loopRuns++; + if (array[i] > max) { + max = array[i]; + } + } + return loopRuns; + } + + public int firstMatch(int[] array0, int[] array1) { + int loopRuns = 0; + for (int i = 0; i < array0.length; i++) { + for (int j = 0; j < array1.length; j++) { + loopRuns++; + if (array0[i] == array1[j]) { + return loopRuns; + } + } + } + return loopRuns; + } + + public void fillArrayRandomRecursively(int[] array, int start, int upperLimit) + { + if (array.length - start <= 0) + { + return; + } + + array[start] = randomInt(upperLimit); + fillArrayRandomRecursively(array, start + 1, upperLimit); + } + + public void testRandomFillRecursively() + { + Util util = new Util(); + int[] valueArray = new int[100]; + util.fillArrayRandomRecursively(valueArray, 0, 100); + util.printArray(valueArray); + } + + public int findMaxBySorting(int[] array){ + Sorter sorter = new Sorter(); + sorter.sort(array); + return array[array.length -1]; + } + + public Integer findValueBySorting(int @NotNull [] array, int value){ + Sorter sorter = new Sorter(); + sorter.sort(array); + int min = array[0]; + int max = array[array.length -1]; + if (value < min || value > max){ + return null; + } + + int low = 0; + int high = array.length - 1; + + while (low <= high) { + int mid = (low + high) >>> 1; + if (array[mid] == value) { + return mid; + } else if (array[mid] < value) { + low = mid + 1; + } else { + high = mid - 1; + } + } + return null; + } + + + +} diff --git a/aufgabenblatt2/src/util/test.java b/aufgabenblatt2/src/util/test.java new file mode 100644 index 0000000..b7f7d82 --- /dev/null +++ b/aufgabenblatt2/src/util/test.java @@ -0,0 +1,10 @@ +package util; + +public class test { + public static void main(String[] args){ + Util util = new Util(); + int[] arr = new int[1000]; + util.fillArrayRandom(arr, 10000); + util.findValueBySorting(arr, 288); + } +}