Add merge sort.

This commit is contained in:
Oleksii Trekhleb 2018-04-14 11:48:33 +03:00
parent b17ba61348
commit ed2abde623
5 changed files with 148 additions and 0 deletions

View File

@ -35,6 +35,7 @@
* [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)
* [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

View File

@ -32,6 +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', 'aa'])).toEqual(['aa', 'aa']);
}

View 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;
}
}

View 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)

View 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,
);
});
});