-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathMergeSort.cs
128 lines (107 loc) · 3.75 KB
/
MergeSort.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Linq;
// Merge sort is a stable sort with O(nlog(n)) time complexity and O(N^2) space complexity.
//
// Compiled: Visual Studio 2013
namespace MergeSort
{
public static class MergeSort
{
public static void Sort(int[] toSort)
{
if (toSort == null) { throw new ArgumentNullException(); }
SortPartition(toSort, 0, toSort.Count() - 1);
}
private static void SortPartition(int[] toSort, int left, int right)
{
// Base case
if (right <= left)
return;
var mid = (right + left) / 2;
SortPartition(toSort, left, mid);
SortPartition(toSort, mid + 1, right);
CombinePartitions(toSort, left, (mid + 1), right);
}
private static void CombinePartitions(int[] toSort, int leftStart, int mid, int rightEnd)
{
var leftPos = leftStart;
int leftEnd = (mid - 1);
var rightPos = mid;
// Create temporary array to hold sorted values
int numElements = (rightEnd - leftStart + 1);
var temp = new int[numElements];
int curr = 0;
// Combining the two sections always taking the smaller element
while (leftPos <= leftEnd && rightPos <= rightEnd)
{
if (toSort[leftPos] <= toSort[rightPos])
temp[curr++] = toSort[leftPos++];
else
temp[curr++] = toSort[rightPos++];
}
// Combine remaining elements in left partition
while (leftPos <= leftEnd)
temp[curr++] = toSort[leftPos++];
// Combine remaining elements in right partition
while (rightPos <= rightEnd)
temp[curr++] = toSort[rightPos++];
// Write back the temporary array elements into the original array
Array.Copy(temp, 0, toSort, leftStart, numElements);
}
}
public static class ArrayExtensions
{
public static void FisherYatesShuffle(this int[] toShuffle)
{
if (toShuffle == null) { throw new ArgumentNullException(); }
int idx = toShuffle.Length - 1;
var rnd = new Random();
while (idx >= 0)
{
var eleToSwap = rnd.Next(idx);
var temp = toShuffle[eleToSwap];
toShuffle[eleToSwap] = toShuffle[idx];
toShuffle[idx] = temp;
idx--;
}
}
}
[TestClass]
public class MergeSortTests
{
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void WhenNull_ExpectArgumentException()
{
int[] array = null;
MergeSort.Sort(array);
}
[TestMethod]
public void WhenZeroElements_ExpectEmpty()
{
var array = new int[0];
MergeSort.Sort(array);
Assert.IsNotNull(array);
Assert.IsFalse(array.Any());
}
[TestMethod]
public void WhenOneElement_ExpectOneElementReturned()
{
var array = new[] { 3 };
MergeSort.Sort(array);
Assert.AreEqual(3, array[0]);
}
[TestMethod]
public void WhenManyElements_ExpectSortedIncreasingOrderIncreasing()
{
const int SIZE = 100;
var original = Enumerable.Range(0, SIZE).ToArray();
var array = new int[SIZE];
Array.Copy(original, array, SIZE);
array.FisherYatesShuffle();
MergeSort.Sort(array);
Assert.IsTrue(array.SequenceEqual(original));
}
}
}