Skip to content

Add in-place sort to QuickSort.js #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
May 27, 2018
2 changes: 1 addition & 1 deletion src/algorithms/sorting/quick-sort/QuickSort.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default class QuickSort extends Sort {
// Clone original array to prevent it from modification.
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) {
return array;
}
Expand Down
59 changes: 59 additions & 0 deletions src/algorithms/sorting/quick-sort/QuickSortInPlace.js
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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,
);
});
});