【问题标题】:Why is insertion sort always beating merge sort in this implementation?为什么在这个实现中插入排序总是击败合并排序?
【发布时间】:2025-12-23 17:45:17
【问题描述】:

我不明白:为什么对于n 的任何大小,我的插入排序实现每次都击败合并排序?

    public List<Int32> InsertionSort(List<Int32> elements, Boolean ascending = true)
    {
        for (Int32 j = 1; j < elements.Count; j++)
        {
            Int32 key = elements[j];
            Int32 i = j - 1;

            while (i >= 0 && (elements[i].CompareTo(key) > 0) == ascending)
                elements[i + 1] = elements[i--];

            elements[i + 1] = key;
        }

        return elements;
    }

    public List<Int32> MergeSort(List<Int32> elements, Boolean ascending = true)
    {
        Sort(elements, 0, elements.Count - 1);

        return elements;
    }

    private void MergeSort(List<Int32> elements, Int32 startIndex, Int32 count)
    {
        if(startIndex < count)
        {
            Int32 half = (startIndex + count).Divide(2, RoundMethod.Floor);
            Sort(elements, startIndex, half);
            Sort(elements, half + 1, count);
            Merge(elements, startIndex, half, count);
        }
    }

    public List<Int32> Merge(List<Int32> elements, Int32 lowerBound, Int32 half, Int32 upperBound)
    {
        Int32 i = 0;
        Int32 j = 0;

        Int32 lowerElementsCount = half - lowerBound + 1;
        Int32 upperElementsCount = upperBound - half;

        List<Int32> left = new List<Int32>();
        while (i < lowerElementsCount)
            left.Add(elements[lowerBound + i++]);

        List<Int32> right = new List<Int32>();
        while (j < upperElementsCount)
            right.Add(elements[half + j++ + 1]);

        left.Add(Int32.MaxValue);
        right.Add(Int32.MaxValue);

        i = 0;
        j = 0;

        for (int k = lowerBound; k <= upperBound; k++)
            if (left[i] <= right[j])
            {
                elements[k] = left[i];
                i++;
            }
            else
            {
                elements[k] = right[j];
                j++;
            }

        return elements;
    }

这是我的结果:

SORTING 1 ELEMENTS
MERGE-SORT: TIME SPENT: 0ms (1513 ticks)
INSERTION-SORT: TIME SPENT: 0ms (1247 ticks)

SORTING 10 ELEMENTS
MERGE-SORT: TIME SPENT: 1ms (2710 ticks)
INSERTION-SORT: TIME SPENT: 0ms (3 ticks)

SORTING 100 ELEMENTS
MERGE-SORT: TIME SPENT: 0ms (273 ticks)
INSERTION-SORT: TIME SPENT: 0ms (11 ticks)

SORTING 1000 ELEMENTS
MERGE-SORT: TIME SPENT: 1ms (3142 ticks)
INSERTION-SORT: TIME SPENT: 0ms (72 ticks)

SORTING 10000 ELEMENTS
MERGE-SORT: TIME SPENT: 18ms (30491 ticks)
INSERTION-SORT: TIME SPENT: 0ms (882 ticks)

以及测试代码:

    static void Main(string[] args)
    {
        for (int i = 1; i < 100000; i*=10)
        {
            List<Int32> elements = GetFilledList(i, 0, Int32.MaxValue, false);
            Console.WriteLine("SORTING {0} ELEMENTS", elements.Count);

            Stopwatch sw = new Stopwatch();

            //MERGE SORT
            sw.Start();
            new MergeSort().Sort(elements);
            sw.Stop();
            Console.WriteLine("MERGE-SORT: TIME SPENT: {0}ms ({1} ticks)", sw.ElapsedMilliseconds, sw.ElapsedTicks);

            //INSERTION SORT
            sw.Restart();
            new InsertionSort().Sort(elements);
            sw.Stop();
            Console.WriteLine("INSERTION-SORT: TIME SPENT: {0}ms ({1} ticks)", sw.ElapsedMilliseconds, sw.ElapsedTicks);
            Console.WriteLine();   
        }

        Console.ReadKey();
    }

如果有人想知道我是从 Introduction to Algorithms, Thomas H. Cormen (Author), Charles E. Leiserson (Author), Ronald L. Rivest (Author), Clifford Stein (Author) 那里得到这些算法的

编辑:

    static List<Int32> GetFilledList(Int32 quantity, Int32 lowerBound, Int32 upperBound, Boolean mayRepeat = true)
    {
        List<Int32> numbers = new List<Int32>();

        Random r = new Random();
        for (int i = 0; i < quantity; i++)
        {
            Int32 numero = r.Next(lowerBound, upperBound); 

            while(!mayRepeat && numbers.Contains(numero))
                numero = r.Next(lowerBound, upperBound);

            numbers.Add(numero);
        }

        return numbers;
    }

【问题讨论】:

    标签: c# algorithm mergesort insertion-sort


    【解决方案1】:

    对 10000 个元素进行排序不足以有效评估算法。做大。

    另外,输入是随机的吗?发布你对GetFilledList的实现

    AND您需要在进行插入排序之前取消对 elements 的排序(或者只是重新初始化 elements)。

    如果你颠倒排序的顺序,会发生什么?我猜您正在合并排序中完成所有工作,然后插入排序只是对 已排序 列表进行排序,实际上它非常擅长(O(n),假设一个理智的实现) .

    【讨论】:

      【解决方案2】:

      因为在归并排序之后,元素中的对象已经排序了。再做一个

      elements = GetFilledList(i, 0, Int32.MaxValue, false);
      

      之前

      sw.Restart();
      

      【讨论】:

        【解决方案3】:

        对于小的输入,插入排序应该比合并排序快;这就是 O(N) 的工作原理。

        f(n) = O(g(n)) if for all n, greater than n0, f(n) < C * g(n)
        

        具有良好复杂性的算法通常具有较高的 C 值,因此在您获得大量输入之前,它们实际上不会开始击败“较慢”的算法。

        虽然 esskar 似乎已经找到了您面临的主要问题,但请记住,将来您可能必须使用大得多的输入来测试算法,才能真正看到更好的算法大放异彩。

        【讨论】: