diff --git a/src/app/constants/UrlConstants.ts b/src/app/constants/UrlConstants.ts index 719b7f1..4c8ce37 100644 --- a/src/app/constants/UrlConstants.ts +++ b/src/app/constants/UrlConstants.ts @@ -6,4 +6,5 @@ static readonly BUBBLE_SORT_WIKI = 'https://de.wikipedia.org/wiki/Bubblesort' static readonly QUICK_SORT_WIKI = 'https://de.wikipedia.org/wiki/Quicksort' static readonly HEAP_SORT_WIKI = 'https://de.wikipedia.org/wiki/Heapsort' + static readonly SHAKE_SORT_WIKI = 'https://de.wikipedia.org/wiki/Shakersort' } diff --git a/src/app/pages/algorithms/sorting/service/sorting.service.ts b/src/app/pages/algorithms/sorting/service/sorting.service.ts index 5bb4d6c..174c8da 100644 --- a/src/app/pages/algorithms/sorting/service/sorting.service.ts +++ b/src/app/pages/algorithms/sorting/service/sorting.service.ts @@ -12,6 +12,7 @@ export class SortingService { }; } + // --- BUBBLE SORT --- bubbleSort(array: SortData[]): SortSnapshot[] { const snapshots: SortSnapshot[] = []; const arr = array.map(item => ({ ...item })); @@ -46,7 +47,60 @@ export class SortingService { return snapshots; } - // --- QUICK SORT --- + // --- COCKTAIL SORT --- + + cocktailSort(array: SortData[]): SortSnapshot[] { + const snapshots: SortSnapshot[] = []; + const arr = array.map(item => ({ ...item })); + snapshots.push(this.createSnapshot(arr)); + + let start = -1; + let end = array.length-1; + let changed = false; + do { + changed = false; + start += 1; + for (let i = start; i < end; i++) { + changed = this.switchValuesIfCorrect(arr, i, snapshots, changed); + } + + //DONE + if (!changed) { + break; + } + + changed = false; + end -= 1; + for (let i = end; i >= start; i--) { + changed = this.switchValuesIfCorrect(arr, i, snapshots, changed); + } + } while (changed); + + + return snapshots; + } + + private switchValuesIfCorrect(arr: { value: number; state: "sorted" | "comparing" | "unsorted" }[], i: number, snapshots: SortSnapshot[], changed: boolean) { + const firstValue = arr[i]; + const secondValue = arr[i + 1]; + + firstValue.state = 'comparing'; + secondValue.state = 'comparing'; + snapshots.push(this.createSnapshot(arr)); + + if (firstValue.value > secondValue.value) { + const temp = firstValue.value; + firstValue.value = secondValue.value; + secondValue.value = temp; + changed = true; + } + firstValue.state = 'unsorted'; + secondValue.state = 'unsorted'; + snapshots.push(this.createSnapshot(arr)); + return changed; + } + +// --- QUICK SORT --- quickSort(array: SortData[]): SortSnapshot[] { const snapshots: SortSnapshot[] = []; const arr = array.map(item => ({ ...item })); diff --git a/src/app/pages/algorithms/sorting/sorting.component.html b/src/app/pages/algorithms/sorting/sorting.component.html index 7880ace..91827b3 100644 --- a/src/app/pages/algorithms/sorting/sorting.component.html +++ b/src/app/pages/algorithms/sorting/sorting.component.html @@ -12,6 +12,11 @@ Wikipedia

+

+ Cocktail Sort {{ 'SORTING.EXPLANATION.COCKTAIL_SORT_EXPLANATION' | translate}} + Wikipedia +

+

Quick Sort {{ 'SORTING.EXPLANATION.QUICK_SORT_EXPLANATION' | translate}} Wikipedia diff --git a/src/app/pages/algorithms/sorting/sorting.component.ts b/src/app/pages/algorithms/sorting/sorting.component.ts index 8cbca5d..97a0670 100644 --- a/src/app/pages/algorithms/sorting/sorting.component.ts +++ b/src/app/pages/algorithms/sorting/sorting.component.ts @@ -1,4 +1,4 @@ -import {ChangeDetectorRef, Component, OnInit} from '@angular/core'; +import {ChangeDetectorRef, Component, inject, OnInit} from '@angular/core'; import { CommonModule } from '@angular/common'; import {MatCardModule} from "@angular/material/card"; import {MatFormFieldModule} from "@angular/material/form-field"; @@ -20,26 +20,28 @@ import {UrlConstants} from '../../../constants/UrlConstants'; }) export class SortingComponent implements OnInit { + private readonly sortingService: SortingService = inject(SortingService); + private readonly cdr: ChangeDetectorRef = inject(ChangeDetectorRef); + readonly MAX_ARRAY_SIZE: number = 200; readonly MIN_ARRAY_SIZE: number = 20; - private timeoutIds: any[] = []; + private timeoutIds: number[] = []; sortArray: SortData[] = []; unsortedArrayCopy: SortData[] = []; - arraySize: number = 100; - maxArrayValue: number = 100; - animationSpeed: number = 50; // Milliseconds per step + arraySize = 50; + maxArrayValue = 100; + animationSpeed = 50; // Milliseconds per step // Placeholder for available sorting algorithms availableAlgorithms: { name: string; value: string }[] = [ { name: 'Bubble Sort', value: 'bubbleSort' }, + { name: 'Cocktail Sort', value: 'cocktailSort' }, { name: 'Quick Sort', value: 'quickSort' }, { name: 'Heap Sort', value: 'heapSort' }, ]; selectedAlgorithm: string = this.availableAlgorithms[0].value; - executionTime: number = 0; - - constructor(private readonly sortingService: SortingService, private readonly cdr: ChangeDetectorRef) { } + executionTime = 0; ngOnInit(): void { this.generateNewArray(); @@ -76,8 +78,8 @@ export class SortingComponent implements OnInit { private resetSortState() { for (let i = 0; i < this.sortArray.length; i++) { - let element = this.sortArray[i]; - let unsortedElement = this.unsortedArrayCopy[i]; + const element = this.sortArray[i]; + const unsortedElement = this.unsortedArrayCopy[i]; element.value = unsortedElement.value; element.state = 'unsorted'; } @@ -98,6 +100,9 @@ export class SortingComponent implements OnInit { case 'heapSort': snapshots = this.sortingService.heapSort(this.sortArray); break; + case 'cocktailSort': + snapshots = this.sortingService.cocktailSort(this.sortArray); + break; } const endTime = performance.now(); diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index a50598d..11c0298 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -334,6 +334,7 @@ "BUBBLE_SORT_EXPLANATION":"vergleicht wiederholt benachbarte Elemente und tauscht sie, wenn sie in der falschen Reihenfolge stehen. Das größte Element \"blubbert\" dabei wie eine Luftblase ans Ende der Liste. Vorteil: Extrem einfach zu verstehen und zu implementieren; erkennt bereits sortierte Listen sehr schnell. Nachteil: Sehr ineffizient bei großen Listen (Laufzeit O(n²)). In der Praxis kaum genutzt.", "QUICK_SORT_EXPLANATION": "folgt dem \"Teile und Herrsche\"-Prinzip. Ein \"Pivot\"-Element wird gewählt, und das Array wird in zwei Hälften geteilt: Elemente kleiner als das Pivot und Elemente größer als das Pivot. Vorteil: Im Durchschnitt einer der schnellsten Sortieralgorithmen (O(n log n)); benötigt keinen zusätzlichen Speicher (In-Place). Nachteil: Im schlechtesten Fall (Worst Case) langsam (O(n²)), wenn das Pivot ungünstig gewählt wird. Ist nicht stabil (ändert Reihenfolge gleicher Elemente).", "HEAP_SORT_EXPLANATION": "organisiert die Daten zunächst in einer speziellen Baumstruktur (Binary Heap). Das größte Element (die Wurzel) wird entnommen und ans Ende sortiert, dann wird der Baum repariert. Vorteil: Garantiert eine schnelle Laufzeit von O(n log n), selbst im schlechtesten Fall. Benötigt fast keinen zusätzlichen Speicher. Nachteil: In der Praxis oft etwas langsamer als Quick Sort, da die Sprünge im Speicher (Heap-Struktur) den CPU-Cache schlechter nutzen.", + "COCKTAIL_SORT_EXPLANATION" : "(auch Shaker Sort) ist eine Erweiterung des Bubble Sort. Statt nur von links nach rechts zu gehen, wechselt er bei jedem Durchlauf die Richtung und schiebt abwechselnd das größte Element nach rechts und das kleinste nach links. Vorteil: Schneller als Bubble Sort, da kleine Elemente am Ende schneller nach vorne wandern (\"Schildkröten-Problem\" gelöst). Nachteil: Bleibt in der Laufzeitklasse O(n²), also für große Datenmengen ineffizient.", "NOTE": "HINWEIS", "DISCLAIMER": "Die Wahl des \"besten\" Sortieralgorithmus hängt stark von den Daten und den Rahmenbedingungen ab. In der Informatik betrachtet man oft drei Szenarien:", "DISCLAIMER_1": "Best Case: Die Daten sind schon fast sortiert (hier glänzt z.B. Bubble Sort).",