Add Cocktail Sort algorithm and UI
Introduce Cocktail (Shaker) Sort to the sorting visualizer: implement cocktailSort and a helper switchValuesIfCorrect in the SortingService to generate snapshots for the animation. Add SHAKE_SORT_WIKI URL constant and a UI paragraph (with a link) plus German translation text for the algorithm explanation. Expose the new algorithm in the component (availableAlgorithms and switch handling). Also refactor the component to use Angular's inject() for SortingService and ChangeDetectorRef, tighten some typings (timeoutIds -> number[]), adjust default arraySize, and use const where appropriate.
This commit is contained in:
@@ -6,4 +6,5 @@
|
|||||||
static readonly BUBBLE_SORT_WIKI = 'https://de.wikipedia.org/wiki/Bubblesort'
|
static readonly BUBBLE_SORT_WIKI = 'https://de.wikipedia.org/wiki/Bubblesort'
|
||||||
static readonly QUICK_SORT_WIKI = 'https://de.wikipedia.org/wiki/Quicksort'
|
static readonly QUICK_SORT_WIKI = 'https://de.wikipedia.org/wiki/Quicksort'
|
||||||
static readonly HEAP_SORT_WIKI = 'https://de.wikipedia.org/wiki/Heapsort'
|
static readonly HEAP_SORT_WIKI = 'https://de.wikipedia.org/wiki/Heapsort'
|
||||||
|
static readonly SHAKE_SORT_WIKI = 'https://de.wikipedia.org/wiki/Shakersort'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export class SortingService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- BUBBLE SORT ---
|
||||||
bubbleSort(array: SortData[]): SortSnapshot[] {
|
bubbleSort(array: SortData[]): SortSnapshot[] {
|
||||||
const snapshots: SortSnapshot[] = [];
|
const snapshots: SortSnapshot[] = [];
|
||||||
const arr = array.map(item => ({ ...item }));
|
const arr = array.map(item => ({ ...item }));
|
||||||
@@ -46,7 +47,60 @@ export class SortingService {
|
|||||||
return snapshots;
|
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[] {
|
quickSort(array: SortData[]): SortSnapshot[] {
|
||||||
const snapshots: SortSnapshot[] = [];
|
const snapshots: SortSnapshot[] = [];
|
||||||
const arr = array.map(item => ({ ...item }));
|
const arr = array.map(item => ({ ...item }));
|
||||||
|
|||||||
@@ -12,6 +12,11 @@
|
|||||||
<a href="{{UrlConstants.BUBBLE_SORT_WIKI}}" target="_blank" rel="noopener noreferrer">Wikipedia</a>
|
<a href="{{UrlConstants.BUBBLE_SORT_WIKI}}" target="_blank" rel="noopener noreferrer">Wikipedia</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<strong>Cocktail Sort</strong> {{ 'SORTING.EXPLANATION.COCKTAIL_SORT_EXPLANATION' | translate}}
|
||||||
|
<a href="{{UrlConstants.SHAKE_SORT_WIKI}}" target="_blank" rel="noopener noreferrer">Wikipedia</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<strong>Quick Sort</strong> {{ 'SORTING.EXPLANATION.QUICK_SORT_EXPLANATION' | translate}}
|
<strong>Quick Sort</strong> {{ 'SORTING.EXPLANATION.QUICK_SORT_EXPLANATION' | translate}}
|
||||||
<a href="{{UrlConstants.QUICK_SORT_WIKI}}" target="_blank" rel="noopener noreferrer">Wikipedia</a>
|
<a href="{{UrlConstants.QUICK_SORT_WIKI}}" target="_blank" rel="noopener noreferrer">Wikipedia</a>
|
||||||
|
|||||||
@@ -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 { CommonModule } from '@angular/common';
|
||||||
import {MatCardModule} from "@angular/material/card";
|
import {MatCardModule} from "@angular/material/card";
|
||||||
import {MatFormFieldModule} from "@angular/material/form-field";
|
import {MatFormFieldModule} from "@angular/material/form-field";
|
||||||
@@ -20,26 +20,28 @@ import {UrlConstants} from '../../../constants/UrlConstants';
|
|||||||
})
|
})
|
||||||
export class SortingComponent implements OnInit {
|
export class SortingComponent implements OnInit {
|
||||||
|
|
||||||
|
private readonly sortingService: SortingService = inject(SortingService);
|
||||||
|
private readonly cdr: ChangeDetectorRef = inject(ChangeDetectorRef);
|
||||||
|
|
||||||
readonly MAX_ARRAY_SIZE: number = 200;
|
readonly MAX_ARRAY_SIZE: number = 200;
|
||||||
readonly MIN_ARRAY_SIZE: number = 20;
|
readonly MIN_ARRAY_SIZE: number = 20;
|
||||||
|
|
||||||
private timeoutIds: any[] = [];
|
private timeoutIds: number[] = [];
|
||||||
sortArray: SortData[] = [];
|
sortArray: SortData[] = [];
|
||||||
unsortedArrayCopy: SortData[] = [];
|
unsortedArrayCopy: SortData[] = [];
|
||||||
arraySize: number = 100;
|
arraySize = 50;
|
||||||
maxArrayValue: number = 100;
|
maxArrayValue = 100;
|
||||||
animationSpeed: number = 50; // Milliseconds per step
|
animationSpeed = 50; // Milliseconds per step
|
||||||
|
|
||||||
// Placeholder for available sorting algorithms
|
// Placeholder for available sorting algorithms
|
||||||
availableAlgorithms: { name: string; value: string }[] = [
|
availableAlgorithms: { name: string; value: string }[] = [
|
||||||
{ name: 'Bubble Sort', value: 'bubbleSort' },
|
{ name: 'Bubble Sort', value: 'bubbleSort' },
|
||||||
|
{ name: 'Cocktail Sort', value: 'cocktailSort' },
|
||||||
{ name: 'Quick Sort', value: 'quickSort' },
|
{ name: 'Quick Sort', value: 'quickSort' },
|
||||||
{ name: 'Heap Sort', value: 'heapSort' },
|
{ name: 'Heap Sort', value: 'heapSort' },
|
||||||
];
|
];
|
||||||
selectedAlgorithm: string = this.availableAlgorithms[0].value;
|
selectedAlgorithm: string = this.availableAlgorithms[0].value;
|
||||||
executionTime: number = 0;
|
executionTime = 0;
|
||||||
|
|
||||||
constructor(private readonly sortingService: SortingService, private readonly cdr: ChangeDetectorRef) { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.generateNewArray();
|
this.generateNewArray();
|
||||||
@@ -76,8 +78,8 @@ export class SortingComponent implements OnInit {
|
|||||||
|
|
||||||
private resetSortState() {
|
private resetSortState() {
|
||||||
for (let i = 0; i < this.sortArray.length; i++) {
|
for (let i = 0; i < this.sortArray.length; i++) {
|
||||||
let element = this.sortArray[i];
|
const element = this.sortArray[i];
|
||||||
let unsortedElement = this.unsortedArrayCopy[i];
|
const unsortedElement = this.unsortedArrayCopy[i];
|
||||||
element.value = unsortedElement.value;
|
element.value = unsortedElement.value;
|
||||||
element.state = 'unsorted';
|
element.state = 'unsorted';
|
||||||
}
|
}
|
||||||
@@ -98,6 +100,9 @@ export class SortingComponent implements OnInit {
|
|||||||
case 'heapSort':
|
case 'heapSort':
|
||||||
snapshots = this.sortingService.heapSort(this.sortArray);
|
snapshots = this.sortingService.heapSort(this.sortArray);
|
||||||
break;
|
break;
|
||||||
|
case 'cocktailSort':
|
||||||
|
snapshots = this.sortingService.cocktailSort(this.sortArray);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const endTime = performance.now();
|
const endTime = performance.now();
|
||||||
|
|||||||
@@ -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.",
|
"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).",
|
"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.",
|
"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",
|
"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": "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).",
|
"DISCLAIMER_1": "Best Case: Die Daten sind schon fast sortiert (hier glänzt z.B. Bubble Sort).",
|
||||||
|
|||||||
Reference in New Issue
Block a user