mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-11-10 11:09:43 +08:00
Add iterative quick sort
This commit is contained in:
parent
afa4948767
commit
152971f801
96
src/algorithms/sorting/quick-sort/QuickSortIterative.js
Normal file
96
src/algorithms/sorting/quick-sort/QuickSortIterative.js
Normal file
@ -0,0 +1,96 @@
|
||||
import Sort from '../Sort';
|
||||
import Stack from '../../../data-structures/stack/Stack';
|
||||
|
||||
export default class QuickSortIterative extends Sort {
|
||||
/**
|
||||
* Iterative Quick Sort
|
||||
*
|
||||
* @param {*[]} originalArray - Not sorted array.
|
||||
* @param {number} inputLowIndex
|
||||
* @param {number} inputHighIndex
|
||||
* @return {*[]} - Sorted array.
|
||||
*/
|
||||
sort(
|
||||
originalArray,
|
||||
inputLowIndex = 0,
|
||||
inputHighIndex = originalArray.length - 1,
|
||||
sortInPlace = true,
|
||||
) {
|
||||
// Copies array on in case we don't want to sort in place
|
||||
const array = sortInPlace ? originalArray : [...originalArray];
|
||||
|
||||
// If array has less than or equal to one elements then it is already sorted.
|
||||
if (array.length <= 1) {
|
||||
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 {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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace recursion with auxiliary stack
|
||||
*/
|
||||
const stack = new Stack();
|
||||
stack.push(inputLowIndex);
|
||||
stack.push(inputHighIndex);
|
||||
|
||||
while (!stack.isEmpty()) {
|
||||
const highIndex = stack.pop();
|
||||
const lowIndex = stack.pop();
|
||||
const partitionIndex = partitionArray(lowIndex, highIndex);
|
||||
|
||||
if (partitionIndex - 1 > lowIndex) {
|
||||
stack.push(lowIndex);
|
||||
stack.push(partitionIndex - 1);
|
||||
}
|
||||
|
||||
if (partitionIndex + 1 < highIndex) {
|
||||
stack.push(partitionIndex + 1);
|
||||
stack.push(highIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
import QuickSortIterative from '../QuickSortIterative';
|
||||
import {
|
||||
equalArr,
|
||||
notSortedArr,
|
||||
reverseArr,
|
||||
sortedArr,
|
||||
SortTester,
|
||||
} from '../../SortTester';
|
||||
|
||||
// Complexity constants.
|
||||
const SORTED_ARRAY_VISITING_COUNT = 19;
|
||||
const NOT_SORTED_ARRAY_VISITING_COUNT = 19;
|
||||
const REVERSE_SORTED_ARRAY_VISITING_COUNT = 19;
|
||||
const EQUAL_ARRAY_VISITING_COUNT = 19;
|
||||
|
||||
describe('QuickSortIterative', () => {
|
||||
it('should sort array', () => {
|
||||
SortTester.testSort(QuickSortIterative);
|
||||
});
|
||||
|
||||
it('should sort array with custom comparator', () => {
|
||||
SortTester.testSortWithCustomComparator(QuickSortIterative);
|
||||
});
|
||||
|
||||
it('should sort negative numbers', () => {
|
||||
SortTester.testNegativeNumbersSort(QuickSortIterative);
|
||||
});
|
||||
|
||||
it('should visit EQUAL array element specified number of times', () => {
|
||||
SortTester.testAlgorithmTimeComplexity(
|
||||
QuickSortIterative,
|
||||
equalArr,
|
||||
EQUAL_ARRAY_VISITING_COUNT,
|
||||
);
|
||||
});
|
||||
|
||||
it('should visit SORTED array element specified number of times', () => {
|
||||
SortTester.testAlgorithmTimeComplexity(
|
||||
QuickSortIterative,
|
||||
sortedArr,
|
||||
SORTED_ARRAY_VISITING_COUNT,
|
||||
);
|
||||
});
|
||||
|
||||
it('should visit NOT SORTED array element specified number of times', () => {
|
||||
SortTester.testAlgorithmTimeComplexity(
|
||||
QuickSortIterative,
|
||||
notSortedArr,
|
||||
NOT_SORTED_ARRAY_VISITING_COUNT,
|
||||
);
|
||||
});
|
||||
|
||||
it('should visit REVERSE SORTED array element specified number of times', () => {
|
||||
SortTester.testAlgorithmTimeComplexity(
|
||||
QuickSortIterative,
|
||||
reverseArr,
|
||||
REVERSE_SORTED_ARRAY_VISITING_COUNT,
|
||||
);
|
||||
});
|
||||
|
||||
it('should sort in place', () => {
|
||||
const sorter = new QuickSortIterative();
|
||||
const originalArray = [7, 5, 1, 42, 30, 24, 14];
|
||||
const sortedArray = sorter.sort(originalArray);
|
||||
expect(originalArray).toEqual(sortedArray);
|
||||
});
|
||||
|
||||
it('should not modify original array', () => {
|
||||
const sorter = new QuickSortIterative();
|
||||
const originalArray = [7, 5, 1, 42, 30, 24, 14];
|
||||
const sortedArray = sorter.sort(originalArray, 0, originalArray.length - 1, false);
|
||||
expect(originalArray).not.toEqual(sortedArray);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user