Spiga

内排序(七):归并排序

2012-07-31 23:47:34

对于排序大列表数据,一个有效的排序算法是归并排序。类似于快速排序算法,其使用的是分治法来排序。归并排序的基本思想是:将两个或两个以上的有序子序列”归并”为一个有序序列。在内部排序中,通常采用的是2-路归并排序。即:将两个位置相邻的有序子序列“归并”为一个有序序列。
一、基本思想

  二路归并排序的基本思想是:将有n个记录的原始序列看作n个有序子序列,每个子序的长度为1,然后从第一个子序列开始,把相邻的子序列两两合关,得到n/2个长度为2或1的子序列(当子序列的个数为奇数时,最后一组合并得到的序列长度为1),我们把这一过程称为一次归并排序,对一次归并排序的n/2个子序列采用上述方法继续顺序成对归并,如此重复,当最后得到长度为n的一个子序列时,该子序列便是原始序列归并排序后的有序序列。

      
    第一步,将列表中的11个元素看成11个有序的序列,每个子序列的长度为1,然后两两归并,得到5个长度为2和1个长度为1的有序子序列。
    第二步,将6个有序子序列两两归并,得到2个长度为4和1个长度为3的有序子序列。
    第三步,将2个长度为4的有序子序列归并,得到第三趟归并结果。
    第四步,将长度为8有序子序列和长度为3的有序子序列归并,得到第四趟归并结果,是长度为11的一个有序子序列。

二、并归排序的实现

public class MergeSort
{
    //P=NP:
    public static List<int> Demo(List<int> data)
    {
        var arr = data.ToArray();
        if (data.Count < 2)
        {
            return data;
        }
        int middle = (int)Math.Floor(((decimal)(data.Count / 2)));
        var left = arr.AsSpan().Slice(0, middle).ToArray();
        var right = arr.AsSpan().Slice(middle).ToArray();
        return Merge(Demo(left.ToList()), Demo(right.ToList()));
    }

    static List<int> Merge(List<int> left, List<int> right)
    {
        var result = new List<int>();

        while (left.Count > 0 && right.Count > 0)
        {
            if (left[0] <= right[0])
            {
                result.Add(left[0]);
                left.RemoveAt(0);
            }
            else
            {
                result.Add(right[0]);
                right.RemoveAt(0);
            }
        }

        while (left.Count != 0)
        {
            result.Add(left[0]);
            left.RemoveAt(0);
        }


        while (right.Count != 0)
        {

            result.Add(right[0]);
            right.RemoveAt(0);
        }

        return result;
    }
}

三、时间复杂度分析

  二路归并排序的时间复杂度为O(nlog2n)。
  二路归并排序算法的空间复杂度为O(n)。