一、原理与分析
归并排序法体现了“分治”思想,相较于前面几篇文章讲过的排序算法,归并排序法具有更好的时间复杂度,但是以牺牲部分空间来换取的。
先看图:
“分治”是将问题划分成逻辑相同,规模更小的子问题,求解子问题后,再将子问题结果合并。归并排序就是将数组分解为两个子数组,将两个子数组排序后在合并排序。对于两个子数组,排序的逻辑与整个数组相同的,因此我们可以用递归求解,当数组长度为1,即只有单个元素时,停止递归。
对于两个数组的合并排序,我们可以用扑克牌来打个比方: 当桌面上有两摞排好序的扑克牌,需要将它们拾起到手中并按大小排好序,我们可以怎么做呢?首先,将两摞扑克牌第一张比较,选取较小的一个拾取,此时被拾取的一摞扑克牌的第一张改变,再将两摞的第一张进行对比……循环此过程,当有一摞扑克牌为空时,直接将另一摞扑克牌全部拿起即可。
二、代码实现
1.将两个子数组合并排序的方法
static int[] Sort(int[] arrLeft, int[] arrRight)
{
int[] array = new int[arrLeft.Length + arrRight.Length];
int i = 0, j = 0, index = 0;
while (i < arrLeft.Length || j < arrRight.Length)
{
if (i >= arrLeft.Length)
{
while (j < arrRight.Length)
{
array[index] = arrRight[j];
index++;
j++;
}
}
else if (j >= arrRight.Length)
{
while (i < arrLeft.Length)
{
array[index] = arrLeft[i];
index++;
i++;
}
}
else
{
if (arrLeft[i] <= arrRight[j])
{
array[index] = arrLeft[i];
i++;
}
else
{
array[index] = arrRight[j];
j++;
}
index++;
}
}
return array;
}
2.将数组分解并递归排序的方法
static int[] Merge(int[] array)
{
if (array.Length <= 1)
return array;
int mid = array.Length / 2;
int[] arrLeft = new int[mid];
int[] arrRight = new int[array.Length - mid];
//将数组拆分成两个部分填入左右两个数组中
for (int i = 0; i < array.Length; i++)
{
if (i < mid)
arrLeft[i] = array[i];
else
arrRight[i - mid] = array[i];
}
return Sort(Merge(arrLeft), Merge(arrRight));
}