diff --git a/22_mergeSort/README.md b/22_mergeSort/README.md new file mode 100644 index 00000000000..52d618e0697 --- /dev/null +++ b/22_mergeSort/README.md @@ -0,0 +1,22 @@ +# Exercise 22 - mergeSort + +A significant amount of computer science is dedicated to sorting data. An algorithm which uses the "divide and conquer" approach +of recursion is able to reduce a sorting problem to smaller and smaller sub-problems. + +Merge sort is one such sorting algorithm, and can be much faster than other algorithms such as bubble sort on the right data sets. + +Essentially, merge sort recurses through an array of unsorted data until it reaches its smallest sub-set, a single item. + +Of course an array with a single item is considered sorted. Merge sort then merges the single items back together in sorted order. Pretty clever! + +To understand what merge sort algorithm is doing check out these resources: +- [Watch this introductory video from Harvard's CS50x course](https://www.youtube.com/watch?v=Ns7tGNbtvV4) +- [Watch this more detailed video explanation by David J. Malan (watch only until 1:58:33)](https://youtu.be/4oqjcKenCH8?t=6248) +- [The concept of merging and Merge Sort - How it Works part on YouTube to give you a more formal look at this problem if you're still unclear](https://youtu.be/mB5HXBb_HY8) +- [Play with this Merge Sort Visualizer to get a better feel for exactly what is happening during a Merge Sort.](https://www.hackerearth.com/practice/algorithms/sorting/merge-sort/visualize/) + +Write a function `mergeSort` that takes in an array and returns a sorted array, using a recursive merge sort methodology. Example: + +```javascript +mergeSort([3, 2, 1, 13, 8, 5, 0, 1]) // [0, 1, 1, 2, 3, 5, 8, 13] +``` diff --git a/22_mergeSort/mergeSort.js b/22_mergeSort/mergeSort.js new file mode 100644 index 00000000000..d64e7a79205 --- /dev/null +++ b/22_mergeSort/mergeSort.js @@ -0,0 +1,6 @@ +const mergeSort = function() { + +}; + +// Do not edit below this line +module.exports = mergeSort; diff --git a/22_mergeSort/mergeSort.spec.js b/22_mergeSort/mergeSort.spec.js new file mode 100644 index 00000000000..67a35b5bdf3 --- /dev/null +++ b/22_mergeSort/mergeSort.spec.js @@ -0,0 +1,15 @@ +const mergeSort = require('./mergeSort'); + +describe('mergeSort', () => { + test('First test description', () => { + // Replace this comment with any other necessary code, and update the expect line as necessary + + expect(mergeSort()).toBe(''); + }); + + test.skip('Second test description', () => { + // Replace this comment with any other necessary code, and update the expect line as necessary + + expect(mergeSort()).toBe(''); + }); +}); diff --git a/22_mergeSort/solution/mergeSort-solution.js b/22_mergeSort/solution/mergeSort-solution.js new file mode 100644 index 00000000000..9195378371b --- /dev/null +++ b/22_mergeSort/solution/mergeSort-solution.js @@ -0,0 +1,27 @@ +function mergeSort(array) { + if (array.length <= 1) return array; + + const midpoint = Math.floor(array.length / 2); + const leftHalf = array.slice(0, midpoint); + const rightHalf = array.slice(midpoint); + + return merge(mergeSort(leftHalf), mergeSort(rightHalf)); +} + +function merge(left, right, merged = [], leftIndex = 0, rightIndex = 0) { + if (leftIndex >= left.length && rightIndex >= right.length) return merged; + + if ( + leftIndex < left.length && + (rightIndex >= right.length || left[leftIndex] < right[rightIndex]) + ) { + merged.push(left[leftIndex]); + return merge(left, right, merged, leftIndex + 1, rightIndex); + } else { + merged.push(right[rightIndex]); + return merge(left, right, merged, leftIndex, rightIndex + 1); + } +} + +// Do not edit below this line +module.exports = mergeSort; diff --git a/22_mergeSort/solution/mergeSort-solution.spec.js b/22_mergeSort/solution/mergeSort-solution.spec.js new file mode 100644 index 00000000000..56fecc7b827 --- /dev/null +++ b/22_mergeSort/solution/mergeSort-solution.spec.js @@ -0,0 +1,45 @@ +const mergeSort = require('./mergeSort-solution'); + +describe('mergeSort', () => { + test('sorts an array of numbers', () => { + expect(mergeSort([4, 1, 3, 9, 7])).toEqual([1, 3, 4, 7, 9]); + }); + + test('returns an empty array when called with an empty array', () => { + expect(mergeSort([])).toEqual([]); + }); + + test('sorts an array with duplicate elements', () => { + expect(mergeSort([5, 3, 8, 3, 2])).toEqual([2, 3, 3, 5, 8]); + }); + + test('sorts an array of negative numbers', () => { + expect(mergeSort([-3, -1, -7, -4])).toEqual([-7, -4, -3, -1]); + }); + + test('sorts an array with negative and positive numbers', () => { + expect(mergeSort([-1, 2, -3, 4, -5])).toEqual([-5, -3, -1, 2, 4]); + }); + + test('sorts an array with one element', () => { + expect(mergeSort([10])).toEqual([10]); + }); + + test('sorts an already sorted array', () => { + expect(mergeSort([1, 2, 3, 4, 5])).toEqual([1, 2, 3, 4, 5]); + }); + + test('sorts an array in descending order', () => { + expect(mergeSort([5, 4, 3, 2, 1])).toEqual([1, 2, 3, 4, 5]); + }); + + test('sorts a large array', () => { + const largeArray = Array.from({ length: 1000 }, () => Math.floor(Math.random() * 1000)); + const sortedArray = [...largeArray].sort((a, b) => a - b); + expect(mergeSort(largeArray)).toEqual(sortedArray); + }); + + test('handles array with all the same elements', () => { + expect(mergeSort([7, 7, 7, 7, 7])).toEqual([7, 7, 7, 7, 7]); + }); +});