1. 程式人生 > 實用技巧 >C#資料結構與算法系列(二十三):歸併排序演算法(MergeSort)

C#資料結構與算法系列(二十三):歸併排序演算法(MergeSort)

1.介紹

歸併排序(MergeSort)是利用歸併的思想實現的排序方法,該演算法採用經典的分治策略(分治法將問題分(divide)成一些小的問題然後遞迴求解,

而治(conquer)的階段則將分的階段得到的各答案“修補”在一起,即分而治之)

2.示意圖

說明:可以看到這種結構很像一顆完全二叉樹,可以採用遞迴和迴圈迭代的方式去實現,分階段可以理解為就是遞迴拆分子序列的過程

合併相鄰有序子序列

再來看看治階段,我們需要將兩個已經有序的子序列合併成一個有序序列,比如上圖中的最後一次合併,

要將[4,5,7,8]和[1,2,3,6]兩個已經有序的子序列,合併為最終序列[1,2,3,4,5,6,7,8],來看下實現步驟

3.例項

把陣列[8,4,5,7,1,3,6,2]使用歸併排序完成排序

    public class MergeSort
    {
        public static void Test()
        {
            int[] arr = { 8, 4, 5, 7, 1, 3, 6, 2 };

            int[] temp = new int[arr.Length];

            Sort(arr,0,arr.Length-1,temp);

            Console.WriteLine(string.Join("
,",arr)); } /// <summary> /// 分+合方法 /// </summary> /// <param name="arr"></param> /// <param name="left"></param> /// <param name="right"></param> /// <param name="temp"></param> private 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; //初始化i,左邊有序序列的初始化索引 int j = mid + 1; //初始化j,右邊有序序列的初始化索引 int t = 0; //指向temp陣列的當前索引 //(一) //先把左右兩邊(有序)的資料按照規則填充到temp陣列 //直到左右兩邊的有序序列,有一邊處理完成為止 while (i <= mid && j <= right) { //如果左邊的有序序列的當前元素,小於或者等於右邊有序序列的當前元素 //即將左邊的當前元素,填充到temp陣列 //然後t++,i++ if (arr[i] <= arr[j]) { temp[t] = arr[i]; t += 1; i += 1; } //反之,將右邊有序序列的當前元素,填充到temp陣列 else { temp[t] = arr[j]; t++; j++; } } //(二) //把有剩餘資料的一邊的資料依次全部填充到temp while (i <= mid) { //左邊的有序序列還有剩餘的元素,就全部填充到temp temp[t] = arr[i]; t++; i++; } while (j <= right) { temp[t] = arr[j]; t++; j++; } //(三) //將temp陣列的元素拷貝到arr,並不是每次都拷貝所有 t = 0; int tempLeft = left; while (tempLeft <= right) //第一次合併 tempLeft=0,right=1 第二次 tempLeft=2 right=3; { arr[tempLeft] = temp[t]; t++; tempLeft++; } } }

結果圖