【数据结构】【C#】021-归并类排序: ✌二路归并(稳定)

归并排序:二路归并(稳定)

基本思想:
归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

【 算法思想 】 假设初始序列含有 n 个记录,首先将这 n 个记录看成 n 个有序的子序列,

每个子序列的长度为 1,然后两两归并,得到 n/2个长度为 2(n 为奇数时,最后一
个序列的长度为 1)的有序子序列;
在此基础上,再对长度为 2 的有序子序列进行两两归并,得到若干个长度为 4 的有
序子序列;如此重复,直至得到一个长度为 n 的有序序列为止。这种方法被称作 2-路归并排序。


二路归并

C# 实现:

递归方式:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 归并排序
/// </summary>
public class MergeSort
{
    
    /// <summary>
    /// 递归分治
    /// </summary>
    /// <param name="a"></param>
    /// <param name="left"></param>
    /// <param name="right"></param>
    public static void SortRecusion(int[] a,int left,int right)
    {
        if (left >= right)
        {
            return;
        }
        int mid = (left + right) / 2;

        SortRecusion(a, left, mid);
        SortRecusion(a, mid + 1, right);
        Merge(a, left, mid, right);        
    }

    /// <summary>
    /// 合并
    /// </summary>
    /// <param name="a"></param>
    /// <param name="left"></param>
    /// <param name="mid"></param>
    /// <param name="rigth"></param>
    public static void Merge(int[] a,int left,int mid,int rigth)
    {
        int[] temp = new int[rigth - left + 1];//中间数组

        int i = left;//左开头
        int j = mid + 1;//右开头

        int k = 0;
        while(i<=mid&&j<=rigth)//把较小的数先移到新数组中
        {
            if(a[i]<=a[j])
            {
                temp[k++] = a[i++];
            }
            else
            {
                temp[k++] = a[j++];
            }
        }
        // 把左边剩余的数移入数组
        while (i<=mid)
        {
            temp[k++] = a[i++];
        }
        // 把右边边剩余的数移入数组
        while (j <= rigth)
        {
            temp[k++] = a[j++];
        }

        // 把新数组中的数覆盖nums数组
        for (int p=0;p<temp.Length;p++)
        {
            a[left + p] = temp[p];
        }



    }
}

非递归方式:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 归并排序
/// </summary>
public class MergeSort
{



    /// <summary>
    /// 非递归
    /// </summary>
    /// <param name="a"></param>
    /// <param name="length"></param>
    public static void SortIteration(int[] a, int length)
    {
        for (int gap = 1; gap < length; gap = 2 * gap)
        {
            MergePass(a, gap, length);
        }
    }

    public static void MergePass(int[] a, int gap, int length)
    {
        int i = 0;
        //归并 gap 长度的两个相邻子表
        for (i = 0; i + 2 * gap - 1 < length; i += 2 * gap)
        {
            Merge(a, i, i + gap - 1, i + 2 * gap - 1);
        }
        //余下两个子表,后者长度小于gap
        if (i + gap - 1 < length)
        {
            Merge(a, i, i + gap - 1, length - 1);
        }
    }

    /// <summary>
    /// 合并
    /// </summary>
    /// <param name="a"></param>
    /// <param name="left"></param>
    /// <param name="mid"></param>
    /// <param name="rigth"></param>
    public static void Merge(int[] a, int left, int mid, int rigth)
    {
        int[] temp = new int[rigth - left + 1];//中间数组

        int i = left;//左开头
        int j = mid + 1;//右开头

        int k = 0;
        while (i <= mid && j <= rigth)//把较小的数先移到新数组中
        {
            if (a[i] <= a[j])
            {
                temp[k++] = a[i++];
            }
            else
            {
                temp[k++] = a[j++];
            }
        }
        // 把左边剩余的数移入数组
        while (i <= mid)
        {
            temp[k++] = a[i++];
        }
        // 把右边边剩余的数移入数组
        while (j <= rigth)
        {
            temp[k++] = a[j++];
        }

        // 把新数组中的数覆盖nums数组
        for (int p = 0; p < temp.Length; p++)
        {
            a[left + p] = temp[p];
        }

    }

}

测试用例:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public class _015_MergeSort : MonoBehaviour
{


    void Start()
    {
        int[] a = Utilit.RandArray(20, 10);

        int[] b = (int[])a.Clone();

        Debug.Log("---------------归并排序:递归--------------");
        MergeSort.SortRecusion(a, 0, a.Length - 1);
        Utilit.Print(a, 0);

        Debug.Log("---------------归并排序:非递归--------------");
        MergeSort.SortIteration(b, b.Length);
        Utilit.Print(b, 0);
    }


}


测试结果:

img.jpg

注:

整个归并排序需进行 m(m=log 2 n)趟 2-路归并,所以归并排序总的时间复杂度为 O(nlog 2 n)。在实现归并排序时,需要和待排记录等数量的辅助空间,空间复杂度为O(n)。

类似 2-路归并排序,可设计多路归并排序法。与快速排序和堆排序相比,归并排序
的最大特点是,它是一种稳定的排序方法。一般情况下,由于要求附加和待排记录等数
量的辅助空间,因此很少利用 2-路归并排序进行内部排序,归并的思想主要用于外部排序。

外部排序可分两步:
①待排序记录分批读入内存,用某种方法在内存排序,组成有序的子文件,再按某种策略存入外存。
②子文件多路归并,成为较长有序子文件,再进入外存,如此反复,直到整个待排序文件有序。
外部排序可使用磁带、磁盘等外存,最初形成有序子文件长取决于内存所能提供排序区大小和最初排序策略,归并路数取决于能提供排序的外部设备数。

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容