• 算法与数据结构——排序(七)归并排序


          归并算法其实理解起来很容易,我们以前在学习C++的时候,肯定遇到过这样一道题目,给两个有序的列表,请把他们合并成一个列表,并且有序。相信叫大家写一个函数实现这个功能并不难。但是我们当时怎么没有想到,用这个思想,可以发明出一种排序的算法出来呢,它就是我们要学习的归并排序。

          归并排序的原理就是,把一个序列拆分成两个小的序列,把这两个 小的序列排好序好,然后再把它们合并起来。对于每个小的序列,我们又可以进行拆分成更小的两个序列,把更小的两个序列排序好后,合并起来。对于更小的序列,我们又可以进行拆分,一直这样拆分,直到拆分到每个序列里面只有一个数的时候,这个时候,就把这个数当作一个列表,跟另外一个列表实现合并,并有序。

    image

          比如我们要排序的序列有10个数,我们可以把这10个数当成10个序列,对每两个序列进行排序并合并成一个序列,这时候,就有了5个序列,然后再把这一个序列里面的两两排序合并,一直到最后合并成了一个序列,那么这个序列也就变成了有序的了。

    image

            上面的就是归并排序的基本原理示意图.最重要的一步就是给你两个有序的列表,把它合并成一个有序的列表,这个方法实现如下:

    /// <summary>
    /// 把两个有序的序列A和B合并到一个有序列temp里面
    /// </summary>
    /// <param name="sortListA">有序序列A</param>
    /// <param name="sortListB">有序序列B</param>
    /// <param name="tempList">有序序列Temp</param>
    public void Merge(List<int> sortListA, List<int> sortListB, List<int> tempList)
    {
        int countB = 0;
        int countA = 0;
        //1.以某个序列为原始序列,把它的每一个数,与另外的一个序列做比较
        for (int i = 0; i < sortListA.Count; i++)
        {
            //1.1循环遍历序列B的每一个序列(因为B序列是有序列的,所以第一个元素是最小的)
            for (int j = countB; j < sortListB.Count; j++)
            {
                //1.2如果A序列中的某个元素比B中的小,就把A中的这个元素加到temp中去
                if (sortListA[i] < sortListB[j])
                {
                    tempList.Add(sortListA[i]);
                    countA++;//记录加到temp中去的A序列中元素的数量 
                    break;
                }
                    //1.2否则把B中的元素加到temp中去
                else
                {
                    tempList.Add(sortListB[j]);
                    countB++;//记录加到temp中去的B序列中元素的数量 
                }
            }
        }//注意,此for循环结束后,一定有一个序列中的元素全部加到了temp中去了。
     
        //如果此处不相等,代表B中的元素还没有加完,那么把B中剩下的元素加入到Temp中去
        if (countB != sortListB.Count)
        {
            for (int k = countB; k < sortListB.Count; k++)
            {
                tempList.Add(sortListB[k]);
            }
        }
        //否则的话,代表A中的元素还没有加完,那么把A中剩下的元素加入到Temp中去
        else
        {
            for (int k = countA; k < sortListA.Count; k++)
            {
                tempList.Add(sortListA[k]);
            }
        }
     
    }

          递归调用的方法如下:

    public void MSort(List<int > sortList, List<int > resultList,int start,int end)
    {
        List<int> tempList1 = new List<int>();
        List<int> tempList2 = new List<int>();
        int mid = (start + end) / 2;
     
        if (start == end)
        {
            resultList.Add(sortList[start]);
        }
        else
        {
            MSort(sortList,  tempList1, start, mid);//递归调用,把SortList里面,第start到mid之间的数,进行归并,结果放在tempList1里面
            MSort(sortList,  tempList2, mid+1, end);//递归调用,把SortList里面,第mid+1到end之间的数,进行归并,结果放在tempList2里面
            //resultList = Merge(tempList1, tempList2);//不能这样调用,
            Merge(tempList1, tempList2, resultList);//把TempList1和TempList2中的数合并到resultList中去
        }
     
    }

          最后实现的排序方法是:

    public List<int> SortByMerge(List<int> sortList)
    {
        List<int> resultList=new List<int>();
        MSort(sortList, resultList, 0, sortList.Count - 1);
        return resultList;
    }
    最后我们来看看归并排序的时间复杂度,由完全二叉树的深度可以知道,归并排序需要进行[log2n次],每趟排序还需要把序列中的每一个元素归并到另外一个序列中去,耗费时间复杂度是O(n),所以总的时间复杂度是O(nlog2n).
  • 相关阅读:
    拓端tecdat| R语言使用Bass模型进行手机市场产品周期预测
    19.纯 CSS 创作一种有削铁如泥感觉的菜单导航特效
    3.div+css 的布局较 table 布局有什么优点
    1.五大浏览器内核
    18.纯 CSS 创作 404 文字变形为 NON 文字的交互特效
    17.1拓展之纯 CSS 创作炫酷的同心圆旋转动画
    17.纯 CSS 创作炫酷的同心矩形旋转动画
    16.纯 CSS 创作一个渐变色动画边框
    15.纯 CSS 创作条形图,不用任何图表库
    14.纯 CSS 创作一种侧立图书的特效
  • 原文地址:https://www.cnblogs.com/xiaoxiangfeizi/p/2758096.html
Copyright © 2020-2023  润新知