Add Task 6 sorter, fix method signatures, generate solution PDF

This commit is contained in:
2026-04-08 20:27:43 +02:00
parent cd51025dc4
commit a958ba600f
7 changed files with 185 additions and 3 deletions

Binary file not shown.

View File

@@ -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.

Binary file not shown.

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}