C#实现选择排序与插入排序:代码、原理与性能对比

青禾
青禾
发布时间:2026-10-16 | 7人浏览过
原创

本文深入解析C#中选择排序与插入排序的实现原理,提供带性能计时的标准代码示例。通过对比分析,明确阐述两者在数据量较大或特定有序状态下的表现差异,帮助开发者根据实际场景选择最优排序策略。

选择排序实现与原理

选择排序(Selection Sort)的基本思想是:每次从未排序区间中找到最小(或最大)元素,存放到排序区间的末尾。对于升序排列,第一轮找出整个数组的最小值并与第一个位置交换;第二轮找出剩余元素的最小值与第二个位置交换,依此类推。

该算法的关键特性在于数据移动次数较少。在内循环中只进行比较,确定最小元素的索引后,才在循环外进行一次交换。这意味着对于长度为 N 的数组,无论初始顺序如何,交换总次数固定为 N 次(准确说是 N-1 次),而比较次数固定为 N(N-1)/2 次。这使得选择排序的时间效率完全取决于比较操作,且对已有序数组的处理时间与随机数组无异。

第1步:编写选择排序类

目的:创建一个包含标准选择排序逻辑的 C# 类,并内置性能计时功能以便后续对比。 入口:新建一个名为 SelectionSort.cs 的文件。 动作:实现 IComparable[] 类型的排序方法,使用 Stopwatch 记录运行耗时。

using System;

public class Selection : BaseSort
{
    public static long usedTimes = 0;
    public Selection()
    {
    }

    public static void Sort(IComparable[] a)
    {
        Stopwatch timer = new Stopwatch();
        timer.Start();

        // 外层循环控制已排序区的边界
        for (var i = 0; i < a.Length - 1; i++)
        {
            int minIndex = i;
            // 内层循环寻找未排序区中的最小值索引
            for (var j = i + 1; j < a.Length; j++)
            {
                if (Less(a[j], a[minIndex]))
                {
                    minIndex = j;
                }
            }

            // 如果找到的最小值不是当前起始位置,则交换
            if (minIndex != i)
            {
                Exch(a, minIndex, i);
            }
        }

        timer.Stop();
        usedTimes = timer.ElapsedMilliseconds;
    }

    // 辅助方法:比较大小
    private static bool Less(IComparable v, IComparable w)
    {
        return v.CompareTo(w) < 0;
    }

    // 辅助方法:交换元素
    private static void Exch(IComparable[] a, int i, int j)
    {
        IComparable t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
}

// 假设 BaseSort 包含基础工具类,此处仅为结构示意
public abstract class BaseSort
{
    protected static bool Less(IComparable v, IComparable w) { throw new NotImplementedException(); }
    protected static void Exch(IComparable[] a, int i, int j) { throw new NotImplementedException(); }
}

插入排序实现与原理

插入排序(Insertion Sort)将数组分为“已排序”和“未排序”两部分。初始时,认为第一个元素是已排序的。随后,依次取出未排序部分的第一个元素,在已排序序列中从后向前扫描,找到合适位置并插入。

与选择排序不同,插入排序的性能高度依赖于输入的初始顺序: 1. 最好情况(数组已有序):只需进行 N-1 次比较,0 次交换,时间复杂度为 O(N)。 2. 最坏情况(数组逆序):需要 ~N²/2 次比较和 ~N²/2 次交换,时间复杂度为 O(N²)。 3. 平均情况:需要 ~N²/4 次比较和交换。但在处理“部分有序”数组(如倒置数量较少、每个元素距离最终位置不远)时,效率极高,甚至优于许多高级排序算法。

第2步:编写插入排序类

目的:实现高效的插入排序,展示如何通过减少数组访问次数来优化性能。 入口:新建 InsertionSort.cs 文件。 动作:提供两种常见实现方式——直接交换法(代码简洁但访问频率高)和位移法(代码稍长但访问频率低,通常更快)。

using System;

public class Insertion : BaseSort
{
    public static long usedTimes = 0;

    public static void Sort(IComparable[] a)
    {
        Stopwatch timer = new Stopwatch();
        timer.Start();

        /*
         * 方式一:直接交换法
         * 逻辑简单,类似冒泡排序的思想,但只向右移动一步。
         * 缺点是频繁访问数组,开销较大。
         */
        for (var i = 1; i < a.Length; i++)
        {
            for (var j = i; j > 0 && Less(a[j], a[j - 1]); j--)
            {
                Exch(a, j, j - 1);
            }
        }

        /*
         * 方式二:位移优化法(推荐)
         * 将当前元素暂存到临时变量 temp,然后将其左侧较大的元素全部右移一位,
         * 最后将 temp 放入正确位置。减少了大量的数组写入操作。
         */
        // int N = a.Length;
        // for (int i = 1; i < N; i++)
        // {
        //     IComparable temp = a[i];
        //     int j;
        //     // 寻找插入位置并右移元素
        //     for (j = i - 1; j >= 0 && Less(temp, a[j]); j--)
        //     {
        //         a[j + 1] = a[j];
        //     }
        //     // 放置临时变量到正确位置
        //     a[j + 1] = temp;
        // }

        timer.Stop();
        usedTimes = timer.ElapsedMilliseconds;
    }
}

// 同样需要 Less 和 Exch 辅助方法,若选用方式二可省略 Exch

两种算法的对比与总结

在实际应用中,插入排序的表现通常优于选择排序,主要原因如下:

  • 自适应能力:插入排序能利用数据的初始有序性。对于几乎有序的数组,其速度接近线性;而选择排序无论输入如何,始终执行平方级的比较。
  • 操作开销:虽然两者的最坏时间复杂度均为 O(N²),但插入排序通过“位移”而非频繁的“两两交换”,减少了内存写操作的次数。一般而言,插入排序的运行时间约为选择排序的一半。
  • 适用场景:当数据规模较小(N 较小)或数据基本有序时,插入排序是极佳的选择。对于大规模随机数据,通常会结合其他高级排序算法(如快速排序或归并排序)使用,或在递归底层切换回插入排序以优化常数因子。

以上就是C#实现选择排序与插入排序的详细对比与代码实践,更多关于C#算法优化的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表