Add in-place sort to QuickSort.js (#16)

* Add in-place sort to QuickSort.js

* Fix linting errors and clean up comments

* Change implementation to address lint errors

* Trailing space and undefined variable

* Create own class for in-place quicksort and use tests

* Add trailing space at end of file

* Fix placement of visitedCallback, explain itial destructuring
This commit is contained in:
Robert Taussig
2018-05-27 16:11:13 -04:00
committed by Oleksii Trekhleb
parent f93d12d5dd
commit bf5d7b338c
3 changed files with 116 additions and 1 deletions

View File

@ -5,7 +5,7 @@ export default class QuickSort extends Sort {
// Clone original array to prevent it from modification. // Clone original array to prevent it from modification.
const array = [...originalArray]; const array = [...originalArray];
// If array has less then or equal to one elements then it is already sorted. // If array has less than or equal to one elements then it is already sorted.
if (array.length <= 1) { if (array.length <= 1) {
return array; return array;
} }

View File

@ -0,0 +1,59 @@
import Sort from '../Sort';
export default class QuickSortInPlace extends Sort {
/* Sorting in place avoids unnecessary use of additional memory, but modifies input array.
*
* This process is difficult to describe, but much clearer with a visualization:
* http://www.algomation.com/algorithm/quick-sort-visualization
*/
sort(originalArray, inputLow, inputHigh) {
// Destructures array on initial passthrough, and then sorts in place.
const array = inputLow === undefined ? [...originalArray] : originalArray;
// Partition array segment and return index of last swap
const partition = (l, h) => {
const swap = (left, right) => {
const tempVariable = array[left];
array[left] = array[right];
array[right] = tempVariable;
};
const pivot = array[h];
this.callbacks.visitingCallback(array[pivot]);
let firstRunner = l - 1;
for (let secondRunner = l; secondRunner < h; secondRunner += 1) {
if (this.comparator.lessThan(array[secondRunner], pivot)) {
firstRunner += 1;
swap(firstRunner, secondRunner);
}
}
if (this.comparator.lessThan(pivot, array[firstRunner + 1])) {
swap(firstRunner + 1, h);
}
return firstRunner + 1;
};
/*
* While we can use a default parameter to set `low` to 0, we would
* still have to set `high`'s default within the function as we
* don't have access to `array.length - 1` when declaring paramaters
*/
const low = inputLow === undefined ? 0 : inputLow;
const high = inputHigh === undefined ? array.length - 1 : inputHigh;
// Base case is when low and high converge
if (low < high) {
const partitionIndex = partition(low, high);
/*
* `partition()` swaps elements of the array based on their comparison to the `hi` parameter,
* and then returns the index where swapping is no longer necessary, which can be best thought
* of as the pivot used to split an array in a non-in-place quicksort
*/
this.sort(array, low, partitionIndex - 1);
this.sort(array, partitionIndex + 1, high);
}
return array;
}
}

View File

@ -0,0 +1,56 @@
import QuickSortInPlace from '../QuickSortInPlace';
import {
equalArr,
notSortedArr,
reverseArr,
sortedArr,
SortTester,
} from '../../SortTester';
// Complexity constants.
const SORTED_ARRAY_VISITING_COUNT = 19;
const NOT_SORTED_ARRAY_VISITING_COUNT = 12;
const REVERSE_SORTED_ARRAY_VISITING_COUNT = 19;
const EQUAL_ARRAY_VISITING_COUNT = 19;
describe('QuickSortInPlace', () => {
it('should sort array', () => {
SortTester.testSort(QuickSortInPlace);
});
it('should sort array with custom comparator', () => {
SortTester.testSortWithCustomComparator(QuickSortInPlace);
});
it('should visit EQUAL array element specified number of times', () => {
SortTester.testAlgorithmTimeComplexity(
QuickSortInPlace,
equalArr,
EQUAL_ARRAY_VISITING_COUNT,
);
});
it('should visit SORTED array element specified number of times', () => {
SortTester.testAlgorithmTimeComplexity(
QuickSortInPlace,
sortedArr,
SORTED_ARRAY_VISITING_COUNT,
);
});
it('should visit NOT SORTED array element specified number of times', () => {
SortTester.testAlgorithmTimeComplexity(
QuickSortInPlace,
notSortedArr,
NOT_SORTED_ARRAY_VISITING_COUNT,
);
});
it('should visit REVERSE SORTED array element specified number of times', () => {
SortTester.testAlgorithmTimeComplexity(
QuickSortInPlace,
reverseArr,
REVERSE_SORTED_ARRAY_VISITING_COUNT,
);
});
});