Skip to content

Commit bf5d7b3

Browse files
robtaussigtrekhleb
authored andcommitted
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
1 parent f93d12d commit bf5d7b3

File tree

3 files changed

+116
-1
lines changed

3 files changed

+116
-1
lines changed

src/algorithms/sorting/quick-sort/QuickSort.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export default class QuickSort extends Sort {
55
// Clone original array to prevent it from modification.
66
const array = [...originalArray];
77

8-
// If array has less then or equal to one elements then it is already sorted.
8+
// If array has less than or equal to one elements then it is already sorted.
99
if (array.length <= 1) {
1010
return array;
1111
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import Sort from '../Sort';
2+
3+
export default class QuickSortInPlace extends Sort {
4+
/* Sorting in place avoids unnecessary use of additional memory, but modifies input array.
5+
*
6+
* This process is difficult to describe, but much clearer with a visualization:
7+
* http://www.algomation.com/algorithm/quick-sort-visualization
8+
*/
9+
sort(originalArray, inputLow, inputHigh) {
10+
// Destructures array on initial passthrough, and then sorts in place.
11+
const array = inputLow === undefined ? [...originalArray] : originalArray;
12+
// Partition array segment and return index of last swap
13+
const partition = (l, h) => {
14+
const swap = (left, right) => {
15+
const tempVariable = array[left];
16+
array[left] = array[right];
17+
array[right] = tempVariable;
18+
};
19+
20+
const pivot = array[h];
21+
this.callbacks.visitingCallback(array[pivot]);
22+
let firstRunner = l - 1;
23+
24+
for (let secondRunner = l; secondRunner < h; secondRunner += 1) {
25+
if (this.comparator.lessThan(array[secondRunner], pivot)) {
26+
firstRunner += 1;
27+
swap(firstRunner, secondRunner);
28+
}
29+
}
30+
31+
if (this.comparator.lessThan(pivot, array[firstRunner + 1])) {
32+
swap(firstRunner + 1, h);
33+
}
34+
35+
return firstRunner + 1;
36+
};
37+
38+
/*
39+
* While we can use a default parameter to set `low` to 0, we would
40+
* still have to set `high`'s default within the function as we
41+
* don't have access to `array.length - 1` when declaring paramaters
42+
*/
43+
const low = inputLow === undefined ? 0 : inputLow;
44+
const high = inputHigh === undefined ? array.length - 1 : inputHigh;
45+
46+
// Base case is when low and high converge
47+
if (low < high) {
48+
const partitionIndex = partition(low, high);
49+
/*
50+
* `partition()` swaps elements of the array based on their comparison to the `hi` parameter,
51+
* and then returns the index where swapping is no longer necessary, which can be best thought
52+
* of as the pivot used to split an array in a non-in-place quicksort
53+
*/
54+
this.sort(array, low, partitionIndex - 1);
55+
this.sort(array, partitionIndex + 1, high);
56+
}
57+
return array;
58+
}
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import QuickSortInPlace from '../QuickSortInPlace';
2+
import {
3+
equalArr,
4+
notSortedArr,
5+
reverseArr,
6+
sortedArr,
7+
SortTester,
8+
} from '../../SortTester';
9+
10+
// Complexity constants.
11+
const SORTED_ARRAY_VISITING_COUNT = 19;
12+
const NOT_SORTED_ARRAY_VISITING_COUNT = 12;
13+
const REVERSE_SORTED_ARRAY_VISITING_COUNT = 19;
14+
const EQUAL_ARRAY_VISITING_COUNT = 19;
15+
16+
describe('QuickSortInPlace', () => {
17+
it('should sort array', () => {
18+
SortTester.testSort(QuickSortInPlace);
19+
});
20+
21+
it('should sort array with custom comparator', () => {
22+
SortTester.testSortWithCustomComparator(QuickSortInPlace);
23+
});
24+
25+
it('should visit EQUAL array element specified number of times', () => {
26+
SortTester.testAlgorithmTimeComplexity(
27+
QuickSortInPlace,
28+
equalArr,
29+
EQUAL_ARRAY_VISITING_COUNT,
30+
);
31+
});
32+
33+
it('should visit SORTED array element specified number of times', () => {
34+
SortTester.testAlgorithmTimeComplexity(
35+
QuickSortInPlace,
36+
sortedArr,
37+
SORTED_ARRAY_VISITING_COUNT,
38+
);
39+
});
40+
41+
it('should visit NOT SORTED array element specified number of times', () => {
42+
SortTester.testAlgorithmTimeComplexity(
43+
QuickSortInPlace,
44+
notSortedArr,
45+
NOT_SORTED_ARRAY_VISITING_COUNT,
46+
);
47+
});
48+
49+
it('should visit REVERSE SORTED array element specified number of times', () => {
50+
SortTester.testAlgorithmTimeComplexity(
51+
QuickSortInPlace,
52+
reverseArr,
53+
REVERSE_SORTED_ARRAY_VISITING_COUNT,
54+
);
55+
});
56+
});

0 commit comments

Comments
 (0)