mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-11-13 06:23:00 +08:00
Add merge sort.
This commit is contained in:
parent
b17ba61348
commit
ed2abde623
@ -35,6 +35,7 @@
|
|||||||
* [Selection Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/selection-sort)
|
* [Selection Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/selection-sort)
|
||||||
* [Insertion Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/insertion-sort)
|
* [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)
|
* [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)
|
||||||
|
|
||||||
## Running Tests
|
## Running Tests
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ export class SortTester {
|
|||||||
expect(sorter.sort([''])).toEqual(['']);
|
expect(sorter.sort([''])).toEqual(['']);
|
||||||
expect(sorter.sort(['a'])).toEqual(['a']);
|
expect(sorter.sort(['a'])).toEqual(['a']);
|
||||||
expect(sorter.sort(['aa', 'a'])).toEqual(['a', 'aa']);
|
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', 'aa'])).toEqual(['aa', 'aa']);
|
expect(sorter.sort(['aa', 'aa'])).toEqual(['aa', 'aa']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
59
src/algorithms/sorting/merge-sort/MergeSort.js
Normal file
59
src/algorithms/sorting/merge-sort/MergeSort.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import Sort from '../Sort';
|
||||||
|
|
||||||
|
export default class MergeSort extends Sort {
|
||||||
|
sort(originalArray) {
|
||||||
|
// Call visiting callback.
|
||||||
|
this.callbacks.visitingCallback(null);
|
||||||
|
|
||||||
|
// If array is empty or consists of one element then return this array since it is sorted.
|
||||||
|
if (originalArray.length <= 1) {
|
||||||
|
return originalArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split array on two halves.
|
||||||
|
const middleIndex = Math.floor(originalArray.length / 2);
|
||||||
|
const leftArray = originalArray.slice(0, middleIndex);
|
||||||
|
const rightArray = originalArray.slice(middleIndex, originalArray.length);
|
||||||
|
|
||||||
|
// Sort two halves of split array
|
||||||
|
const leftSortedArray = this.sort(leftArray);
|
||||||
|
const rightSortedArray = this.sort(rightArray);
|
||||||
|
|
||||||
|
// Merge two sorted arrays into one.
|
||||||
|
return this.mergeSortedArrays(leftSortedArray, rightSortedArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
mergeSortedArrays(leftArray, rightArray) {
|
||||||
|
let sortedArray = [];
|
||||||
|
|
||||||
|
// In case if arrays are not of size 1.
|
||||||
|
while (leftArray.length && rightArray.length) {
|
||||||
|
let minimumElement = null;
|
||||||
|
|
||||||
|
// Find minimum element of two arrays.
|
||||||
|
if (this.comparator.lessThenOrEqual(leftArray[0], rightArray[0])) {
|
||||||
|
minimumElement = leftArray.shift();
|
||||||
|
} else {
|
||||||
|
minimumElement = rightArray.shift();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call visiting callback.
|
||||||
|
this.callbacks.visitingCallback(minimumElement);
|
||||||
|
|
||||||
|
// Push the minimum element of two arrays to the sorted array.
|
||||||
|
sortedArray.push(minimumElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If one of two array still have elements we need to just concatenate
|
||||||
|
// this element to the sorted array since it is already sorted.
|
||||||
|
if (leftArray.length) {
|
||||||
|
sortedArray = sortedArray.concat(leftArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rightArray.length) {
|
||||||
|
sortedArray = sortedArray.concat(rightArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sortedArray;
|
||||||
|
}
|
||||||
|
}
|
27
src/algorithms/sorting/merge-sort/README.md
Normal file
27
src/algorithms/sorting/merge-sort/README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Merge Sort
|
||||||
|
|
||||||
|
In computer science, merge sort (also commonly spelled
|
||||||
|
mergesort) is an efficient, general-purpose,
|
||||||
|
comparison-based sorting algorithm. Most implementations
|
||||||
|
produce a stable sort, which means that the implementation
|
||||||
|
preserves the input order of equal elements in the sorted
|
||||||
|
output. Mergesort is a divide and conquer algorithm that
|
||||||
|
was invented by John von Neumann in 1945.
|
||||||
|
|
||||||
|
An example of merge sort. First divide the list into
|
||||||
|
the smallest unit (1 element), then compare each
|
||||||
|
element with the adjacent list to sort and merge the
|
||||||
|
two adjacent lists. Finally all the elements are sorted
|
||||||
|
and merged.
|
||||||
|
|
||||||
|
![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/c/cc/Merge-sort-example-300px.gif)
|
||||||
|
|
||||||
|
A recursive merge sort algorithm used to sort an array of 7
|
||||||
|
integer values. These are the steps a human would take to
|
||||||
|
emulate merge sort (top-down).
|
||||||
|
|
||||||
|
![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/e/e6/Merge_sort_algorithm_diagram.svg)
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
[Wikipedia](https://en.wikipedia.org/wiki/Merge_sort)
|
60
src/algorithms/sorting/merge-sort/__test__/MergeSort.test.js
Normal file
60
src/algorithms/sorting/merge-sort/__test__/MergeSort.test.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import BubbleSort from '../MergeSort';
|
||||||
|
import {
|
||||||
|
equalArr,
|
||||||
|
notSortedArr,
|
||||||
|
reverseArr,
|
||||||
|
sortedArr,
|
||||||
|
SortTester,
|
||||||
|
} from '../../SortTester';
|
||||||
|
|
||||||
|
// Complexity constants.
|
||||||
|
const SORTED_ARRAY_VISITING_COUNT = 79;
|
||||||
|
const NOT_SORTED_ARRAY_VISITING_COUNT = 102;
|
||||||
|
const REVERSE_SORTED_ARRAY_VISITING_COUNT = 87;
|
||||||
|
const EQUAL_ARRAY_VISITING_COUNT = 79;
|
||||||
|
|
||||||
|
describe('MergeSort', () => {
|
||||||
|
it('should sort array', () => {
|
||||||
|
SortTester.testSort(BubbleSort);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should sort array with custom comparator', () => {
|
||||||
|
SortTester.testSortWithCustomComparator(BubbleSort);
|
||||||
|
});
|
||||||
|
|
||||||
|
// it('should do stable sorting', () => {
|
||||||
|
// SortTester.testSortStability(BubbleSort);
|
||||||
|
// });
|
||||||
|
|
||||||
|
it('should visit EQUAL array element specified number of times', () => {
|
||||||
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
|
BubbleSort,
|
||||||
|
equalArr,
|
||||||
|
EQUAL_ARRAY_VISITING_COUNT,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should visit SORTED array element specified number of times', () => {
|
||||||
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
|
BubbleSort,
|
||||||
|
sortedArr,
|
||||||
|
SORTED_ARRAY_VISITING_COUNT,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should visit NOT SORTED array element specified number of times', () => {
|
||||||
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
|
BubbleSort,
|
||||||
|
notSortedArr,
|
||||||
|
NOT_SORTED_ARRAY_VISITING_COUNT,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should visit REVERSE SORTED array element specified number of times', () => {
|
||||||
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
|
BubbleSort,
|
||||||
|
reverseArr,
|
||||||
|
REVERSE_SORTED_ARRAY_VISITING_COUNT,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user