算法系列05---归并排序
一、归并排序描述
把长度为n的输入序列分成两个长度为n/2的子序列;
对这两个子序列分别采用归并排序;
将两个排序好的子序列合并成一个最终的排序序列。
将两个的有序数列合并成一个有序数列,我们称之为"归并"。
归并排序(Merge Sort)就是利用归并思想对数列进行排序。根据具体的实现,归并排序包括"从上往下"和"从下往上"2种方式。
-
1、从下往上的归并排序:将待排序的数列分成若干个长度为1的子数列,然后将这些数列两两合并;得到若干个长度为2的有序数列,再将这些数列两两合并;得到若干个长度为4的有序数列,再将它们两两合并;直接合并成一个数列为止。这样就得到了我们想要的排序结果。(参考下面的图片)
-
2、从上往下的归并排序:它与"从下往上"在排序上是反方向的。它基本包括3步:
- ① 分解:将当前区间一分为二,即求分裂点 mid = (low + high)/2;
- ② 求解:递归地对两个子区间a[low...mid] 和 a[mid+1...high]进行归并排序。递归的终结条件是子区间长度为1。
- ③ 合并:将已排序的两个子区间a[low...mid]和 a[mid+1...high]归并为一个有序的区间a[low...high]。
三、代码实现
public class MergeSort { public static void Sort(int[] arr,int left,int right,int[] temp) { if(left<right) { int mid = (left + right) / 2; Sort(arr, left, mid, temp); Sort(arr, mid + 1, right, temp); Merge(arr, left, mid, right, temp); } } /// <summary> /// 归并 /// </summary> /// <param name="arr">原始数组</param> /// <param name="left">左边有序序列初始索引</param> /// <param name="mid">中间索引</param> /// <param name="right">右边有序序列初始索引</param> /// <param name="temp">中转数组</param> private static void Merge(int[] arr, int left, int mid, int right, int[] temp) { int i = left; int j = mid + 1; int t = 0; while(i<=mid && j<=right) { //如果左边的有序序列的当前元素小于等于右边的有序序列的当前元素,则将左边的当前元素拷贝到temp数组 if(arr[i]<=arr[j]) { temp[t] = arr[i]; t+=1; i+=1; } else { //否则,将右边的当前元素拷贝到temp数组 temp[t] = arr[j]; t+=1; j+=1; } } //左边有序序列剩余的元素全部填充到temp while(i<=mid) { temp[t] = arr[i]; t+=1; i+=1; } //右边的有序序列剩余元素全部填充到temp while(j<=right) { temp[t] = arr[j]; t+=1; j+=1; } //将temp数组的元素拷贝到arr t = 0; int tempLeft = left; while(tempLeft <=right) { arr[tempLeft] = temp[t]; t+=1; tempLeft+=1; } } }