mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-11-13 06:23:00 +08:00
Compare commits
2 Commits
b87b7b75a2
...
8c2bef086d
Author | SHA1 | Date | |
---|---|---|---|
|
8c2bef086d | ||
|
ef95c02318 |
113
src/algorithms/sorting/tim-sort/TimSort.js
Normal file
113
src/algorithms/sorting/tim-sort/TimSort.js
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/* eslint-disable linebreak-style */
|
||||||
|
/* eslint-disable operator-assignment */
|
||||||
|
/* eslint-disable no-param-reassign */
|
||||||
|
/* eslint-disable linebreak-style */
|
||||||
|
/* eslint-disable no-plusplus */
|
||||||
|
import Sort from '../Sort';
|
||||||
|
|
||||||
|
export default class TimSort extends Sort {
|
||||||
|
sort(originalArray) {
|
||||||
|
let RUN = 32;
|
||||||
|
const array = [...originalArray];
|
||||||
|
if (array.length < RUN) RUN = RUN / 2 + 1;
|
||||||
|
|
||||||
|
for (let i = 0; i < array.length; i += RUN) {
|
||||||
|
this.insertionSort(array, i, Math.min(i + RUN - 1, array.length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let size = RUN; size < array.length; size = 2 * size) {
|
||||||
|
for (let left = 0; left < array.length; left += 2 * size) {
|
||||||
|
// find ending point of
|
||||||
|
// left sub array
|
||||||
|
// mid+1 is starting point
|
||||||
|
// of right sub array
|
||||||
|
const mid = left + size - 1;
|
||||||
|
const right = Math.min(left + 2 * size - 1, array.length - 1);
|
||||||
|
|
||||||
|
// merge sub array arr[left.....mid] &
|
||||||
|
// arr[mid+1....right]
|
||||||
|
this.merge(array, left, mid, right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
insertionSort(originalArray, leftIndex, rightIndex) {
|
||||||
|
// Go through leftIndex to rightIndex Elements
|
||||||
|
for (let i = leftIndex; i <= rightIndex; i += 1) {
|
||||||
|
let currentIndex = i;
|
||||||
|
|
||||||
|
// Call visiting callback.
|
||||||
|
this.callbacks.visitingCallback(originalArray[i]);
|
||||||
|
|
||||||
|
// Go and check if previous elements and greater then current one.
|
||||||
|
// If this is the case then swap that elements.
|
||||||
|
while (
|
||||||
|
originalArray[currentIndex - 1] !== undefined
|
||||||
|
&& this.comparator.lessThan(
|
||||||
|
originalArray[currentIndex],
|
||||||
|
originalArray[currentIndex - 1],
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// Call visiting callback.
|
||||||
|
this.callbacks.visitingCallback(originalArray[currentIndex - 1]);
|
||||||
|
|
||||||
|
// Swap the elements.
|
||||||
|
[originalArray[currentIndex - 1], originalArray[currentIndex]] = [
|
||||||
|
originalArray[currentIndex],
|
||||||
|
originalArray[currentIndex - 1],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Shift current index left.
|
||||||
|
currentIndex -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
merge(originalArray, l, m, r) {
|
||||||
|
// Original array is broken in two parts
|
||||||
|
// left and right array
|
||||||
|
const len1 = m - l + 1;
|
||||||
|
const len2 = r - m;
|
||||||
|
|
||||||
|
const left = [];
|
||||||
|
const right = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < len1; i++) left[i] = originalArray[l + i];
|
||||||
|
for (let i = 0; i < len2; i++) right[i] = originalArray[m + 1 + i];
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
let j = 0;
|
||||||
|
let k = left;
|
||||||
|
|
||||||
|
// After comparing, we
|
||||||
|
// merge those two array
|
||||||
|
// in larger sub array
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
while (i < len1 && j < len2 && left[i] !== undefined && right[j] !== undefined && originalArray[k] !== undefined) {
|
||||||
|
if (this.comparator.lessThan(left[i], right[j])) {
|
||||||
|
originalArray[k] = left[i];
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
originalArray[k] = right[j];
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy remaining elements of left, if any
|
||||||
|
while (i < len1 && left[i] !== undefined && originalArray[k] !== undefined) {
|
||||||
|
originalArray[k] = left[i];
|
||||||
|
k++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy remaining element of right, if any
|
||||||
|
while (j < len2 && right[j] !== undefined && originalArray[k] !== undefined) {
|
||||||
|
originalArray[k] = right[j];
|
||||||
|
k++;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
66
src/algorithms/sorting/tim-sort/__test__/TimSort.test.js
Normal file
66
src/algorithms/sorting/tim-sort/__test__/TimSort.test.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/* eslint-disable linebreak-style */
|
||||||
|
import TimSort from '../TimSort';
|
||||||
|
|
||||||
|
import {
|
||||||
|
equalArr,
|
||||||
|
notSortedArr,
|
||||||
|
reverseArr,
|
||||||
|
sortedArr,
|
||||||
|
SortTester,
|
||||||
|
} from '../../SortTester';
|
||||||
|
|
||||||
|
// Complexity constants.
|
||||||
|
const SORTED_ARRAY_VISITING_COUNT = 20;
|
||||||
|
const NOT_SORTED_ARRAY_VISITING_COUNT = 101;
|
||||||
|
const REVERSE_SORTED_ARRAY_VISITING_COUNT = 210;
|
||||||
|
const EQUAL_ARRAY_VISITING_COUNT = 20;
|
||||||
|
|
||||||
|
describe('TimSort', () => {
|
||||||
|
it('should sort array', () => {
|
||||||
|
SortTester.testSort(TimSort);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should sort array with custom comparator', () => {
|
||||||
|
SortTester.testSortWithCustomComparator(TimSort);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do stable sorting', () => {
|
||||||
|
SortTester.testSortStability(TimSort);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should sort negative numbers', () => {
|
||||||
|
SortTester.testNegativeNumbersSort(TimSort);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should visit EQUAL array element specified number of times', () => {
|
||||||
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
|
TimSort,
|
||||||
|
equalArr,
|
||||||
|
EQUAL_ARRAY_VISITING_COUNT,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should visit SORTED array element specified number of times', () => {
|
||||||
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
|
TimSort,
|
||||||
|
sortedArr,
|
||||||
|
SORTED_ARRAY_VISITING_COUNT,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should visit NOT SORTED array element specified number of times', () => {
|
||||||
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
|
TimSort,
|
||||||
|
notSortedArr,
|
||||||
|
NOT_SORTED_ARRAY_VISITING_COUNT,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should visit REVERSE SORTED array element specified number of times', () => {
|
||||||
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
|
TimSort,
|
||||||
|
reverseArr,
|
||||||
|
REVERSE_SORTED_ARRAY_VISITING_COUNT,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user