Add Task 6 sorter, fix method signatures, generate solution PDF
This commit is contained in:
BIN
aufgabenblatt1/src/aufgabenblatt1-1.pdf
Normal file
BIN
aufgabenblatt1/src/aufgabenblatt1-1.pdf
Normal file
Binary file not shown.
@@ -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.
|
||||
|
||||
BIN
aufgabenblatt1/src/solution.pdf
Normal file
BIN
aufgabenblatt1/src/solution.pdf
Normal file
Binary file not shown.
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
65
aufgabenblatt1/src/task6/Sorter.java
Normal file
65
aufgabenblatt1/src/task6/Sorter.java
Normal 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);
|
||||
}
|
||||
}
|
||||
90
aufgabenblatt1/src/task6/SorterAI.java
Normal file
90
aufgabenblatt1/src/task6/SorterAI.java
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user