mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-11-10 11:09:43 +08:00
Add quick sort.
This commit is contained in:
parent
250d90af3c
commit
c7110be47e
@ -36,7 +36,8 @@
|
||||
* [Insertion Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/insertion-sort)
|
||||
* [Heap Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/heap-sort)
|
||||
* [Merge Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/merge-sort)
|
||||
* [Quick Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/quick-sort)
|
||||
* [Quicksort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/quick-sort)
|
||||
* [Shellsort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/shell-sort)
|
||||
|
||||
## Running Tests
|
||||
|
||||
@ -107,10 +108,11 @@ Below is the list of some of the most used Big O notations and their performance
|
||||
### Array Sorting Algorithms Complexity
|
||||
|
||||
| Name | Best | Average | Worst | Memory | Stable |
|
||||
| --------------------- | :-------: | :-------: | :-------: | :-------: | :-------: |
|
||||
| --------------------- | :-------: | :-------: | :-----------: | :-------: | :-------: |
|
||||
| **Bubble sort** | n | n^2 | n^2 | 1 | Yes |
|
||||
| **Insertion sort** | n | n^2 | n^2 | 1 | Yes |
|
||||
| **Selection sort** | n^2 | n^2 | n^2 | 1 | No |
|
||||
| **Heap sort** | n log(n) | n log(n) | n log(n) | 1 | No |
|
||||
| **Merge sort** | n log(n) | n log(n) | n log(n) | n | Yes |
|
||||
| **Quick sort** | n log(n) | n log(n) | n^2 | log(n) | No |
|
||||
| **Shell sort** | n log(n) | depends on gap sequence | n (log(n))^2 | 1 | No |
|
||||
|
@ -32,7 +32,7 @@ export class SortTester {
|
||||
expect(sorter.sort([''])).toEqual(['']);
|
||||
expect(sorter.sort(['a'])).toEqual(['a']);
|
||||
expect(sorter.sort(['aa', 'a'])).toEqual(['a', 'aa']);
|
||||
expect(sorter.sort(['aa', 'q', 'a', 'bbbb', 'ccc'])).toEqual(['q', 'a', 'aa', 'ccc', 'bbbb']);
|
||||
expect(sorter.sort(['aa', 'q', 'bbbb', 'ccc'])).toEqual(['q', 'aa', 'ccc', 'bbbb']);
|
||||
expect(sorter.sort(['aa', 'aa'])).toEqual(['aa', 'aa']);
|
||||
}
|
||||
|
||||
@ -49,6 +49,7 @@ export class SortTester {
|
||||
const sorter = new SortingClass(callbacks);
|
||||
|
||||
expect(sorter.sort(['bb', 'aa', 'c'])).toEqual(['c', 'bb', 'aa']);
|
||||
expect(sorter.sort(['aa', 'q', 'a', 'bbbb', 'ccc'])).toEqual(['q', 'a', 'aa', 'ccc', 'bbbb']);
|
||||
}
|
||||
|
||||
static testAlgorithmTimeComplexity(SortingClass, arrayToBeSorted, numberOfVisits) {
|
||||
|
48
src/algorithms/sorting/shell-sort/README.md
Normal file
48
src/algorithms/sorting/shell-sort/README.md
Normal file
@ -0,0 +1,48 @@
|
||||
# Shellsort
|
||||
|
||||
Shellsort, also known as Shell sort or Shell's method,
|
||||
is an in-place comparison sort. It can be seen as either a
|
||||
generalization of sorting by exchange (bubble sort) or sorting
|
||||
by insertion (insertion sort). The method starts by sorting
|
||||
pairs of elements far apart from each other, then progressively
|
||||
reducing the gap between elements to be compared. Starting
|
||||
with far apart elements, it can move some out-of-place
|
||||
elements into position faster than a simple nearest neighbor
|
||||
exchange
|
||||
|
||||
![Shellsort](https://upload.wikimedia.org/wikipedia/commons/d/d8/Sorting_shellsort_anim.gif)
|
||||
|
||||
## How Shell Sort Works
|
||||
|
||||
For our example and ease of understanding, we take the interval
|
||||
of `4`. Make a virtual sub-list of all values located at the
|
||||
interval of 4 positions. Here these values are
|
||||
`{35, 14}`, `{33, 19}`, `{42, 27}` and `{10, 44}`
|
||||
|
||||
![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_gap_4.jpg)
|
||||
|
||||
We compare values in each sub-list and swap them (if necessary)
|
||||
in the original array. After this step, the new array should
|
||||
look like this
|
||||
|
||||
![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_step_1.jpg)
|
||||
|
||||
Then, we take interval of 2 and this gap generates two sub-lists
|
||||
- `{14, 27, 35, 42}`, `{19, 10, 33, 44}`
|
||||
|
||||
![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_gap_2.jpg)
|
||||
|
||||
We compare and swap the values, if required, in the original array.
|
||||
After this step, the array should look like this
|
||||
|
||||
![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_step_2.jpg)
|
||||
|
||||
Finally, we sort the rest of the array using interval of value 1.
|
||||
Shell sort uses insertion sort to sort the array.
|
||||
|
||||
![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort.jpg)
|
||||
|
||||
## References
|
||||
|
||||
* [Tutorials Point](https://www.tutorialspoint.com/data_structures_algorithms/shell_sort_algorithm.htm)
|
||||
* [Wikipedia](https://en.wikipedia.org/wiki/Shellsort)
|
41
src/algorithms/sorting/shell-sort/ShellSort.js
Normal file
41
src/algorithms/sorting/shell-sort/ShellSort.js
Normal file
@ -0,0 +1,41 @@
|
||||
import Sort from '../Sort';
|
||||
|
||||
export default class ShellSort extends Sort {
|
||||
sort(originalArray) {
|
||||
// Prevent original array from mutations.
|
||||
const array = originalArray.slice(0);
|
||||
|
||||
// Define a gap distance.
|
||||
let gap = Math.floor(array.length / 2);
|
||||
|
||||
// Until gap is bigger then zero do elements comparisons and swaps.
|
||||
while (gap > 0) {
|
||||
// Go and compare all distant element pairs.
|
||||
for (let i = 0; i < (array.length - gap); i += 1) {
|
||||
let currentIndex = i;
|
||||
let gapShiftedIndex = i + gap;
|
||||
|
||||
while (currentIndex >= 0) {
|
||||
// Call visiting callback.
|
||||
this.callbacks.visitingCallback(array[currentIndex]);
|
||||
|
||||
// Compare and swap array elements if needed.
|
||||
if (this.comparator.lessThen(array[gapShiftedIndex], array[currentIndex])) {
|
||||
const tmp = array[currentIndex];
|
||||
array[currentIndex] = array[gapShiftedIndex];
|
||||
array[gapShiftedIndex] = tmp;
|
||||
}
|
||||
|
||||
gapShiftedIndex = currentIndex;
|
||||
currentIndex -= gap;
|
||||
}
|
||||
}
|
||||
|
||||
// Shrink the gap.
|
||||
gap = Math.floor(gap / 2);
|
||||
}
|
||||
|
||||
// Return sorted copy of an original array.
|
||||
return array;
|
||||
}
|
||||
}
|
56
src/algorithms/sorting/shell-sort/__test__/ShellSort.test.js
Normal file
56
src/algorithms/sorting/shell-sort/__test__/ShellSort.test.js
Normal file
@ -0,0 +1,56 @@
|
||||
import ShellSort from '../ShellSort';
|
||||
import {
|
||||
equalArr,
|
||||
notSortedArr,
|
||||
reverseArr,
|
||||
sortedArr,
|
||||
SortTester,
|
||||
} from '../../SortTester';
|
||||
|
||||
// Complexity constants.
|
||||
const SORTED_ARRAY_VISITING_COUNT = 320;
|
||||
const NOT_SORTED_ARRAY_VISITING_COUNT = 320;
|
||||
const REVERSE_SORTED_ARRAY_VISITING_COUNT = 320;
|
||||
const EQUAL_ARRAY_VISITING_COUNT = 320;
|
||||
|
||||
describe('ShellSort', () => {
|
||||
it('should sort array', () => {
|
||||
SortTester.testSort(ShellSort);
|
||||
});
|
||||
|
||||
it('should sort array with custom comparator', () => {
|
||||
SortTester.testSortWithCustomComparator(ShellSort);
|
||||
});
|
||||
|
||||
it('should visit EQUAL array element specified number of times', () => {
|
||||
SortTester.testAlgorithmTimeComplexity(
|
||||
ShellSort,
|
||||
equalArr,
|
||||
EQUAL_ARRAY_VISITING_COUNT,
|
||||
);
|
||||
});
|
||||
|
||||
it('should visit SORTED array element specified number of times', () => {
|
||||
SortTester.testAlgorithmTimeComplexity(
|
||||
ShellSort,
|
||||
sortedArr,
|
||||
SORTED_ARRAY_VISITING_COUNT,
|
||||
);
|
||||
});
|
||||
|
||||
it('should visit NOT SORTED array element specified number of times', () => {
|
||||
SortTester.testAlgorithmTimeComplexity(
|
||||
ShellSort,
|
||||
notSortedArr,
|
||||
NOT_SORTED_ARRAY_VISITING_COUNT,
|
||||
);
|
||||
});
|
||||
|
||||
it('should visit REVERSE SORTED array element specified number of times', () => {
|
||||
SortTester.testAlgorithmTimeComplexity(
|
||||
ShellSort,
|
||||
reverseArr,
|
||||
REVERSE_SORTED_ARRAY_VISITING_COUNT,
|
||||
);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user