Add TimSort implementation and UI entries
Introduce TimSort support across the app: add TIM_SORT_WIKI to UrlConstants, implement timSort (with insertionSortRange and mergeRanges) in SortingService to produce SortSnapshot sequences (uses RUN=32, sorts runs then merges, marks comparing/unsorted/sorted states), and wire the algorithm into SortingComponent (UI entry and case branch). Also add TIMSORT_EXPLANATION translations in de.json and en.json, and add a few UI label keys (STIFFNESS, ELONGATION, RESTART_SIMULATION) to both locale files.
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
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'
|
||||
static readonly TIM_SORT_WIKI = 'https://de.wikipedia.org/wiki/Timsort'
|
||||
static readonly CONWAYS_WIKI = 'https://de.wikipedia.org/wiki/Conways_Spiel_des_Lebens'
|
||||
static readonly PRIMS_WIKI = 'https://de.wikipedia.org/wiki/Algorithmus_von_Prim'
|
||||
static readonly KRUSKAL_WIKI = 'https://de.wikipedia.org/wiki/Algorithmus_von_Kruskal'
|
||||
|
||||
@@ -224,6 +224,103 @@ export class SortingService {
|
||||
}
|
||||
}
|
||||
|
||||
// --- TIM SORT ---
|
||||
timSort(array: SortData[]): SortSnapshot[] {
|
||||
const snapshots: SortSnapshot[] = [];
|
||||
const arr = array.map(item => ({ ...item }));
|
||||
const n = arr.length;
|
||||
const RUN = 32;
|
||||
|
||||
snapshots.push(this.createSnapshot(arr));
|
||||
|
||||
// Step 1: Sort small runs with insertion sort
|
||||
for (let i = 0; i < n; i += RUN) {
|
||||
const end = Math.min(i + RUN - 1, n - 1);
|
||||
this.insertionSortRange(arr, i, end, snapshots);
|
||||
}
|
||||
|
||||
// Step 2: Merge the sorted runs
|
||||
for (let size = RUN; size < n; size *= 2) {
|
||||
for (let left = 0; left < n; left += 2 * size) {
|
||||
const mid = Math.min(left + size - 1, n - 1);
|
||||
const right = Math.min(left + 2 * size - 1, n - 1);
|
||||
if (mid < right) {
|
||||
this.mergeRanges(arr, left, mid, right, snapshots);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arr.forEach(item => item.state = 'sorted');
|
||||
snapshots.push(this.createSnapshot(arr));
|
||||
|
||||
return snapshots;
|
||||
}
|
||||
|
||||
private insertionSortRange(arr: SortData[], left: number, right: number, snapshots: SortSnapshot[]): void {
|
||||
for (let i = left + 1; i <= right; i++) {
|
||||
const tempValue = arr[i].value;
|
||||
arr[i].state = 'comparing';
|
||||
snapshots.push(this.createSnapshot(arr));
|
||||
|
||||
let j = i - 1;
|
||||
while (j >= left && arr[j].value > tempValue) {
|
||||
arr[j].state = 'comparing';
|
||||
arr[j + 1].value = arr[j].value;
|
||||
arr[j].state = 'unsorted';
|
||||
snapshots.push(this.createSnapshot(arr));
|
||||
j--;
|
||||
}
|
||||
|
||||
arr[j + 1].value = tempValue;
|
||||
arr[i].state = 'unsorted';
|
||||
snapshots.push(this.createSnapshot(arr));
|
||||
}
|
||||
}
|
||||
|
||||
private mergeRanges(arr: SortData[], left: number, mid: number, right: number, snapshots: SortSnapshot[]): void {
|
||||
const leftPart = arr.slice(left, mid + 1).map(item => ({ ...item }));
|
||||
const rightPart = arr.slice(mid + 1, right + 1).map(item => ({ ...item }));
|
||||
|
||||
let i = 0;
|
||||
let j = 0;
|
||||
let k = left;
|
||||
|
||||
while (i < leftPart.length && j < rightPart.length) {
|
||||
// Highlight the write target and the right-side source (arr[mid+1+j] is still
|
||||
// untouched in the array since k never overtakes it during a merge)
|
||||
const rightSourceIdx = mid + 1 + j;
|
||||
arr[k].state = 'comparing';
|
||||
arr[rightSourceIdx].state = 'comparing';
|
||||
snapshots.push(this.createSnapshot(arr));
|
||||
|
||||
arr[rightSourceIdx].state = 'unsorted';
|
||||
|
||||
if (leftPart[i].value <= rightPart[j].value) {
|
||||
arr[k].value = leftPart[i].value;
|
||||
i++;
|
||||
} else {
|
||||
arr[k].value = rightPart[j].value;
|
||||
j++;
|
||||
}
|
||||
|
||||
arr[k].state = 'unsorted';
|
||||
k++;
|
||||
snapshots.push(this.createSnapshot(arr));
|
||||
}
|
||||
|
||||
while (i < leftPart.length) {
|
||||
arr[k].value = leftPart[i].value;
|
||||
i++;
|
||||
k++;
|
||||
}
|
||||
|
||||
while (j < rightPart.length) {
|
||||
arr[k].value = rightPart[j].value;
|
||||
j++;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
private swap(arr: SortData[], i: number, j: number) {
|
||||
const temp = arr[i].value;
|
||||
arr[i].value = arr[j].value;
|
||||
|
||||
@@ -49,6 +49,11 @@ export class SortingComponent implements OnInit {
|
||||
name: 'Heap Sort',
|
||||
description: 'SORTING.EXPLANATION.HEAP_SORT_EXPLANATION',
|
||||
link: UrlConstants.HEAP_SORT_WIKI
|
||||
},
|
||||
{
|
||||
name: 'Tim Sort',
|
||||
description: 'SORTING.EXPLANATION.TIMSORT_EXPLANATION',
|
||||
link: UrlConstants.TIM_SORT_WIKI
|
||||
}
|
||||
],
|
||||
disclaimer: 'SORTING.EXPLANATION.DISCLAIMER',
|
||||
@@ -130,6 +135,9 @@ export class SortingComponent implements OnInit {
|
||||
case 'Cocktail Sort':
|
||||
snapshots = this.sortingService.cocktailSort(this.sortArray);
|
||||
break;
|
||||
case 'Tim Sort':
|
||||
snapshots = this.sortingService.timSort(this.sortArray);
|
||||
break;
|
||||
}
|
||||
|
||||
const endTime = performance.now();
|
||||
|
||||
Reference in New Issue
Block a user