implement Tim Sort

This commit is contained in:
Mohammadjafari80 2020-12-21 20:26:21 +03:30
parent 4b6c601158
commit ef95c02318
2 changed files with 179 additions and 0 deletions

View 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++;
}
}
}

View 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,
);
});
});