diff --git a/aufgabenblatt1/src/aufgabenblatt1-1.pdf b/aufgabenblatt1/src/aufgabenblatt1-1.pdf new file mode 100644 index 0000000..b2cc956 Binary files /dev/null and b/aufgabenblatt1/src/aufgabenblatt1-1.pdf differ diff --git a/aufgabenblatt1/src/solution.md b/aufgabenblatt1/src/solution.md index a4bf207..bd847cd 100644 --- a/aufgabenblatt1/src/solution.md +++ b/aufgabenblatt1/src/solution.md @@ -102,3 +102,30 @@ Beide Lösungen liefern **identische Ergebnisse** für alle getesteten Werte. De - **Sonderfälle:** Die KI behandelt Zahlen < 2 und die Zahl 2 explizit als Sonderfälle. **Bewertung:** Die KI-Lösung ist **besser**. Durch die Optimierung der Schleifengrenze auf √n und das Überspringen gerader Zahlen sinkt die Gesamtkomplexität von O(n²) auf ca. O(n√n) — bei maximum = 200.000 ein erheblicher Geschwindigkeitsvorteil. Die Ergebnisse sind trotzdem identisch. + +# Task 6 + +## Strategie & Laufzeitkomplexität + +Mein Ansatz verwendet **Natural Merge Sort**. Der Algorithmus erkennt bereits sortierte Teilfolgen (Runs) im Array und verschmilzt jeweils benachbarte Paare. Dieser Vorgang wird wiederholt, bis das gesamte Array sortiert ist. + +**Laufzeitkomplexität: O(n log n)** im Worst Case, **O(n)** im Best Case (bereits sortiertes Array), da dann nur ein einziger Durchlauf ohne Merges nötig ist. Der Speicherbedarf ist O(n) für das temporäre Array. + +## Vergleich: Eigene Lösung vs. KI-Lösung + +Die KI verwendet **Introsort** — einen Hybridalgorithmus aus Quicksort, Heapsort und Insertion Sort. Dies ist der gleiche Ansatz, den die meisten Standardbibliotheken (z.B. C++ `std::sort`) verwenden. + +**Gemeinsamkeiten:** +- Beide Algorithmen haben eine Worst-Case-Komplexität von O(n log n) +- Beide liefern korrekte, identische Sortier-Ergebnisse +- Beide verwenden Hilfsmethoden zur Modularisierung + +**Unterschiede:** +- **Algorithmus-Familie:** Meine Lösung ist ein reiner Merge Sort (iterativ, bottom-up). Die KI kombiniert drei verschiedene Algorithmen je nach Situation. +- **Adaptivität:** Meine Lösung nutzt natürliche Runs — bei teilweise vorsortierten Daten ist sie schneller. Die KI wechselt bei kleinen Teilarrays (< 16 Elemente) zu Insertion Sort und bei zu tiefer Rekursion zu Heapsort. +- **Speicher:** Meine Lösung benötigt O(n) zusätzlichen Speicher für das temp-Array. Die KI sortiert in-place mit nur O(log n) Speicher für den Rekursionsstack. +- **Stabilität:** Meine Lösung ist **stabil** (gleiche Elemente behalten ihre Reihenfolge). Die KI-Lösung ist **nicht stabil** (Quicksort-Partition kann die Reihenfolge gleicher Elemente ändern). +- **Komplexität des Codes:** Meine Lösung ist deutlich kürzer und einfacher zu verstehen. Die KI-Lösung hat 5 separate Methoden (introsort, partition, heapsort, heapify, insertionSort). +- **Pivot-Wahl:** Die KI verwendet Median-of-Three für die Pivot-Wahl, was Worst-Case-Verhalten bei bereits sortierten Arrays vermeidet. + +**Bewertung:** Beide Lösungen sind **gleichwertig gut**, mit unterschiedlichen Stärken. Meine Lösung ist einfacher, stabil und optimal bei teilweise vorsortierten Daten. Die KI-Lösung ist speichereffizienter und garantiert O(n log n) auch im Worst Case durch den Heapsort-Fallback. diff --git a/aufgabenblatt1/src/solution.pdf b/aufgabenblatt1/src/solution.pdf new file mode 100644 index 0000000..d773719 Binary files /dev/null and b/aufgabenblatt1/src/solution.pdf differ diff --git a/aufgabenblatt1/src/task3/NumberGuesser.java b/aufgabenblatt1/src/task3/NumberGuesser.java index 47db76c..f7e3081 100644 --- a/aufgabenblatt1/src/task3/NumberGuesser.java +++ b/aufgabenblatt1/src/task3/NumberGuesser.java @@ -30,8 +30,8 @@ public class NumberGuesser { while (low <= high) { int mid = low + (high - low) / 2; + System.out.println("Guess: " + mid); if (mid == number) { - System.out.println("Found the number: " + mid); return; } else if (isBigger(mid)) { low = mid + 1; diff --git a/aufgabenblatt1/src/task5/PrimeNumberGenerator.java b/aufgabenblatt1/src/task5/PrimeNumberGenerator.java index e77b020..6bccbdd 100644 --- a/aufgabenblatt1/src/task5/PrimeNumberGenerator.java +++ b/aufgabenblatt1/src/task5/PrimeNumberGenerator.java @@ -21,7 +21,7 @@ public class PrimeNumberGenerator { } return true; } - private int countPrimes() { + public int countPrimeNumbers() { int count = 0; for (int i = 2; i <= maximum; i++) { if (isPrime(i)) { @@ -37,7 +37,7 @@ public class PrimeNumberGenerator { System.out.println("maximum,Anzahl Primzahlen (Algorithmus),maximum/ln(maximum) (Schätzung)"); for (int max : testValues) { PrimeNumberGenerator generator = new PrimeNumberGenerator(max); - int counted = generator.countPrimes(); + int counted = generator.countPrimeNumbers(); double estimated = max / Math.log(max); System.out.printf("%d,%d,%.1f%n", max, counted, estimated); } diff --git a/aufgabenblatt1/src/task6/Sorter.java b/aufgabenblatt1/src/task6/Sorter.java new file mode 100644 index 0000000..3036d3a --- /dev/null +++ b/aufgabenblatt1/src/task6/Sorter.java @@ -0,0 +1,65 @@ +package task6; + +import util.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 static final void main(String[] args) { + int[] array = new int[100]; + Util util = new Util(); + util.fillArrayRandom(array, 100); + Sorter mySorter = new Sorter(); + mySorter.sort(array); + util.printArray(array); + } +} diff --git a/aufgabenblatt1/src/task6/SorterAI.java b/aufgabenblatt1/src/task6/SorterAI.java new file mode 100644 index 0000000..82fb777 --- /dev/null +++ b/aufgabenblatt1/src/task6/SorterAI.java @@ -0,0 +1,90 @@ +package task6; + +import util.Util; + +public class SorterAI { + public void sort(int[] array) { + if (array == null || array.length <= 1) return; + introsort(array, 0, array.length - 1, 2 * (int) Math.floor(Math.log(array.length) / Math.log(2))); + } + + private void introsort(int[] array, int low, int high, int depthLimit) { + if (high - low < 16) { + insertionSort(array, low, high); + return; + } + if (depthLimit == 0) { + heapsort(array, low, high); + return; + } + int pivot = partition(array, low, high); + introsort(array, low, pivot - 1, depthLimit - 1); + introsort(array, pivot + 1, high, depthLimit - 1); + } + + private int partition(int[] 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); + if (array[mid] < array[high]) swap(array, mid, high); + int pivot = array[high]; + + int i = low - 1; + for (int j = low; j < high; j++) { + if (array[j] <= pivot) { + swap(array, ++i, j); + } + } + swap(array, i + 1, high); + return i + 1; + } + + private void heapsort(int[] array, int low, int high) { + int n = high - low + 1; + for (int i = n / 2 - 1; i >= 0; i--) + heapify(array, low, n, i); + for (int i = n - 1; i > 0; i--) { + swap(array, low, low + i); + heapify(array, low, i, 0); + } + } + + private void heapify(int[] array, int offset, int n, int i) { + int largest = i; + int left = 2 * i + 1; + int right = 2 * i + 2; + if (left < n && array[offset + left] > array[offset + largest]) largest = left; + if (right < n && array[offset + right] > array[offset + largest]) largest = right; + if (largest != i) { + swap(array, offset + i, offset + largest); + heapify(array, offset, n, largest); + } + } + + private void insertionSort(int[] array, int low, int high) { + for (int i = low + 1; i <= high; i++) { + int key = array[i]; + int j = i - 1; + while (j >= low && array[j] > key) { + array[j + 1] = array[j]; + j--; + } + array[j + 1] = key; + } + } + + private void swap(int[] 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]; + Util util = new Util(); + util.fillArrayRandom(array, 100); + SorterAI mySorter = new SorterAI(); + mySorter.sort(array); + util.printArray(array); + } +}