Skip to content
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

Refactor QuickSortInPlace #239

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 42 additions & 60 deletions src/algorithms/sorting/quick-sort/QuickSortInPlace.js
Original file line number Diff line number Diff line change
@@ -6,73 +6,55 @@ export default class QuickSortInPlace extends Sort {
* This process is difficult to describe, but much clearer with a visualization:
* @see: http://www.algomation.com/algorithm/quick-sort-visualization
*
* @param {*[]} originalArray - Not sorted array.
* @param {*[]} array - Not sorted array.
* @param {number} inputLowIndex
* @param {number} inputHighIndex
* @param {boolean} recursiveCall
* @return {*[]} - Sorted array.
* @return {*[]} array - Sorted array.
*/
sort(
originalArray,
inputLowIndex = 0,
inputHighIndex = originalArray.length - 1,
recursiveCall = false,
) {
// Copies array on initial call, and then sorts in place.
const array = recursiveCall ? originalArray : [...originalArray];

/**
* The partitionArray() operates on the subarray between lowIndex and highIndex, inclusive.
* It arbitrarily chooses the last element in the subarray as the pivot.
* Then, it partially sorts the subarray into elements than are less than the pivot,
* and elements that are greater than or equal to the pivot.
* Each time partitionArray() is executed, the pivot element is in its final sorted position.
*
* @param {number} lowIndex
* @param {number} highIndex
* @return {number}
*/
const partitionArray = (lowIndex, highIndex) => {
/**
* Swaps two elements in array.
* @param {number} leftIndex
* @param {number} rightIndex
*/
const swap = (leftIndex, rightIndex) => {
const temp = array[leftIndex];
array[leftIndex] = array[rightIndex];
array[rightIndex] = temp;
};

const pivot = array[highIndex];
// visitingCallback is used for time-complexity analysis.
this.callbacks.visitingCallback(array[pivot]);

let partitionIndex = lowIndex;
for (let currentIndex = lowIndex; currentIndex < highIndex; currentIndex += 1) {
if (this.comparator.lessThan(array[currentIndex], pivot)) {
swap(partitionIndex, currentIndex);
partitionIndex += 1;
}
}

// The element at the partitionIndex is guaranteed to be greater than or equal to pivot.
// All elements to the left of partitionIndex are guaranteed to be less than pivot.
// Swapping the pivot with the partitionIndex therefore places the pivot in its
// final sorted position.
swap(partitionIndex, highIndex);

return partitionIndex;
};

sort(array, inputLowIndex = 0, inputHighIndex = array.length - 1) {
// Base case is when low and high converge.
if (inputLowIndex < inputHighIndex) {
const partitionIndex = partitionArray(inputLowIndex, inputHighIndex);
const RECURSIVE_CALL = true;
this.sort(array, inputLowIndex, partitionIndex - 1, RECURSIVE_CALL);
this.sort(array, partitionIndex + 1, inputHighIndex, RECURSIVE_CALL);
const partitionIndex = this.partitionArray(array, inputLowIndex, inputHighIndex);
this.sort(array, inputLowIndex, partitionIndex - 1);
this.sort(array, partitionIndex + 1, inputHighIndex);
}

return array;
}

/**
* The partitionArray() operates on the subarray between lowIndex and highIndex, inclusive.
* It arbitrarily chooses the last element in the subarray as the pivot.
* Then, it partially sorts the subarray into elements than are less than the pivot,
* and elements that are greater than or equal to the pivot.
* Each time partitionArray() is executed, the pivot element is in its final sorted position.
*
* @param {*[]} array - Array for partitioning
* @param {number} lowIndex
* @param {number} highIndex
* @return {number} - Partition index
*/
partitionArray(array, lowIndex, highIndex) {
const pivot = array[highIndex];

// visitingCallback is used for time-complexity analysis.
this.callbacks.visitingCallback(pivot);

let partitionIndex = lowIndex;
for (let currentIndex = lowIndex; currentIndex < highIndex; currentIndex += 1) {
if (this.comparator.lessThan(array[currentIndex], pivot)) {
/* eslint no-param-reassign: ["error", { "props": false }] */
[array[partitionIndex], array[currentIndex]] = [array[currentIndex], array[partitionIndex]];
partitionIndex += 1;
}
}

// The element at the partitionIndex is guaranteed to be greater than or equal to pivot.
// All elements to the left of partitionIndex are guaranteed to be less than pivot.
// Swapping the pivot with the partitionIndex therefore places the pivot in its
// final sorted position.
[array[partitionIndex], array[highIndex]] = [array[highIndex], array[partitionIndex]];

return partitionIndex;
}
}
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ import {

// Complexity constants.
const SORTED_ARRAY_VISITING_COUNT = 19;
const NOT_SORTED_ARRAY_VISITING_COUNT = 12;
const NOT_SORTED_ARRAY_VISITING_COUNT = 19;
const REVERSE_SORTED_ARRAY_VISITING_COUNT = 19;
const EQUAL_ARRAY_VISITING_COUNT = 19;