归并排序是用分治思想,分治模式在每一层递归上有三个步骤:
分解(Divide):将n个元素分成个含n/2个元素的子序列。
解决(Conquer):用合并排序法对两个子序列递归的排序。
合并(Combine):合并两个已排序的子序列已得到排序结果。
归并排序时间复杂度O(nlogn),每次归并处理n个,归并logn次。
归并排序空间复杂度O(n),其实是长度n的临时数组和logn的压入栈的数据,默认就是O(n)了。
用递归实现:
private void MergeSort(int[] arr, int[] tempArr, int start, int end)
{
if(start >= end)
return;
// 求出中间的索引
int mid = ((end - start) >> 1) + 1;
// 区分左边和右边
int start1 = start, end1 = mid;
int start2 = mid + 1, end2 = end;
// (先分解)对左边进行归并, 对右边进行归并
MergeSort(arr, tempArr, start1, end1);
MergeSort(arr, tempArr, start2, end2);
// 循环比较两部分的头,小的先入临时数组,直到一方全部入完
//(递归的最深层,左右两部分都是一个元素,相当于start1 = end1 start2 = end2)
// (从最深层开始往上归并,元素数量开始合并,且按序排列完成)
int k = start;
while(start1 <= end1 && start2 <= end2)
tempArr[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
// 只剩下1部分了,全部移到临时数组后面
while(start1 <= end1)
tempArr[k++] = arr[start1++];
// 只剩下2部分了,全部移到临时数组后面
while(start2 <= end2)
tempArr[k++] = arr[start2++];
//将临时数组 完成排序的部分 替换到原数组上
for(k = start; k <= end; k++)
{
arr[k] = tempArr[k];
}
}
void mergeSort(int[] arr, int len) {
int[] seg = new int[len];
MergeSort(arr, seg, 0, len - 1);
}
用迭代实现:
思路:第一层for循环控制步长,第二层循环对每个排序单元进行排序。
为了方便理解,举一个例子:
假设有一个长度为10的数组要处理
for (int seg = 1; seg < len; seg += seg)
{
// seg = 1,2,4,8
for (int start = 0; start < len; start += seg + seg)
{
//seg = 1, start = 0,2,4,6,8 0-2,2-4,4-6,6-8,8-10之间的分两组先排
//seg = 2, start = 0,4,8 0-4,4-8,8-10之间的分两组排
//seg = 4, start = 0,8 0-8,8-10之间的分两组排
//seg = 8, start = 0 0-10之间的分两组排
}
}
实现
private void MergeSort(int[] arr, int len)
{
int[] tempArr = new int[len];
// 步长控制分解长度, 分组处理
for(int seg = 1; seg < len; seg += seg)
{
// 按照步长,依次处理步长单元内的排序
for(int start = 0; start < len; start += seg + seg)
{
// 确定每个步长单元内的起始位,中间位,结尾位
int low = start, mid = Math.Min(start + seg, len), high = Math.Min(start + seg + seg, len);
int k = low;
// 人为将步长内的元素分成两组,进行排序
//(最开始的轮次, 两组内的元素个数都是1, 随着循环轮次增加,组内元素越来越多,归并的过程)
int start1 = low, end1 = mid;
int start2 = mid, end2 = high;
// 循环比较两组的头,小的先入临时数组,直到一方全部入完
// 这里判断不能用=, 因为high 可能会越界
while(start1 < end1 && start2 < end2)
tempArr[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
while(start1 < end1)
tempArr[k++] = arr[start1++];
while(start2 < end2)
tempArr[k++] = arr[start2++];
}
// 将排好序的数组替换到原数组上,继续循环
int[] temp = arr;
arr = tempArr;
tempArr = temp;
}
}
void mergeSort(int[] arr, int len) {
MergeSort(arr, len);
}