归并排序是利用归并的思想实现的排序方法,该算法采用经典的分治策略。
思路
- 使用递归
- 每次递归都把整个序列分成两份,获得这次分解的范围,left索引到right索引,还要获得这个返回的中间索引mid
- 分解完成后从栈顶开始合并分解最小的基本单元
- 在合并的过程中定义两个指针,i和j,i指左边部分的开始索引,mid指的是中间索引,j指右边部分的开始索引,mid+1
- 左边,右边两个部分独立都是有序的序列,如果左边i元素<右边j元素,就把i元素放入temp中,左边指针后移,反之,如果右边j元素<左边i元素,就把j元素放入temp中,右边指针后移
- 当其中一边的数据全部放入temp中,就把另一边的剩余数据顺序的放入temp中
- 最后在把temp中的数据拷贝到原数组的left到right这一段的位置
- 如上递归完成
图解

这是归并排序的主要过程,先分解数据成最小的基本单元,然后再逐步的合并
再来看看治阶段,我们需要将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],来看下实现步骤。
代码
```csharp using System; using System.Collections.Generic;
namespace ConsoleApp1 { class Program {
static void Main(string[] args){int[] arr = new int[10] { 4, 9, 76, 43, 2, 7, 23, 54, 1, 44 };int[] temp = new int[arr.Length];//归并排序需要一个额外的空间开销MergeSort(arr, 0, arr.Length - 1, temp);foreach(int a in arr){Console.Write(a+" ");}}static void MergeSort(int[] array,int left,int right,int[] temp){if (left < right){int mid = (left + right) / 2;//中间的索引//向左递归进行分解MergeSort(array, left, mid, temp);//向右递归进行分解MergeSort(array, mid + 1, right, temp);//合并//最后一次分解是在栈顶,合并就是栈顶传入的数据merge(array, left, mid, right, temp);}}/// <summary>/// 合并的方法/// </summary>/// <param name="array">排序的原始数组</param>/// <param name="left">左边有序序列的初始索引</param>/// <param name="mid">中间索引</param>/// <param name="right">右边索引</param>/// <param name="temp">做中转的数组</param>static void merge(int[] array,int left,int mid,int right,int[] temp){int i = left;//左边有序序列的初始索引int j = mid + 1;//右边有序序列的初始索引int t = 0;//temp数组的当前索引/*(一)先把左右两边有序的数据,按规则填充到temp数组里面知道左右两边的有序序列,有一边处理完毕为止*/while (i <= mid && j <= right){if (array[i] <= array[j])//如果左边的数小于等于右边的数,就把左边的数放在temp当前的位置,然后i和t都往后移temp[t++] = array[i++];else//反之,如上temp[t++] = array[j++];}/*(二)把有剩余数据的一边的数据依次全部填充到temp*/while (i <= mid)//左边的有序数列还有剩余元素,就全部填充到temptemp[t++] = array[i++];while (j <= right)//反之,同上temp[t++] = array[j++];/*(三)将temp数组的元素拷贝到arr*///拷贝到的array的具体位置,就是left到right中间这一段t = 0;while (left <= right)array[left++] = temp[t++];}}
}
```
