• 插入排序:直接插入排序&希尔排序


    一、直接插入排序

    1. 思想

    直接排序法, 可以分为两个部分, 一部分是有序的, 一部分是无序的.

    从这个图上, 应该是能看清楚直接插入排序的思想了.

    将无序部分的第一个与有序部分进行比较.

    从有序部分的后面向前面比较, 然后不断地挪动有序部分的数据的位置

    static void InsertSort(List<int> list)
    {
       //从第二个数开始循环, 循环n-1次
    for (int i = 1; i < list.Count; i++) {
         //将待排序的数拿出来, 以便后面挪位子
    int temp = list[i];
         //j就是最后确定的那个最大/最小数的下标
    int j = i; while (j >= 1 && temp < list[j - 1]) {
           //将满足条件的数据向后移动一位, 腾空位, 为插入挪位子 list[j]
    = list[j - 1]; j--; } list[j] = temp; } }

    2. 复杂度

    直接插入排序的最好情况下, 时间复杂度为O(n), 最坏情况下, 复杂度为O(n2);

    证明见:

    插入排序及其复杂度分析

    3. 直接插入排序vs快速排序

     从上面的代码来看, 直接插入排序需要不断地挪数据. 如果碰到连续整数, 那么挪动的数据就多了. 针对这种问题, 是否可以改进一下直接插入排序?

    在比较的时候, 我是否可以跳着比较?

    二、希尔排序

    1. 思想

    在比较的时候, 引入缩小增量比较的方式.

    第一步. 使增量d=count/2, 将每隔d个数看成是一组无序的数, 然后对这组无序的数进行插入排序

    第二步. 使增量d=d/2, 和第一步执行相同的操作, 一直到d=1的时候

    代码:

    static void ShellSort(List<int> list)
    {
        int step = list.Count / 2;
        while (step >= 1)
        {
            for (int i = step; i < list.Count; i++)
            {
                var temp = list[i];
                int j = i;
                while (j >= step && temp < list[j - step])
                {
                    list[j] = list[j - step];
                    j -= step;
                }
                list[j] = temp;
            }
            step = step / 2;
        }
    }

    希尔排序与直接插入排序, 中间部分的代码基本一直, 不同的只是维度, 直接插入排序的维度是固定的1,

    而希尔排序的维度是变化的. 从代码上看, 其实还是蛮简单的, 就拿着直接插入排序改吧改吧就成了.

    2. 复杂度

    希尔排序的时间复杂度, 和直接插入排序的最好&最坏时间复杂度居然是一样的, 同志们, 能相信么.

    三、直接插入排序 vs 希尔排序

    既然说希尔排序是直接插入排序的改进版, 那么他们究竟谁更厉害些呢? 会不会越改越差了?

    static void Test()
    {
        //五次比较
        for (int i = 1; i <= 5; i++)
        {
            List<int> list = new List<int>();
            List<int> listA = new List<int>();
            //插入2k个随机数到数组中
            for (int j = 0; j < 10000; j++)
            {
                Thread.Sleep(1);
                list.Add(new Random((int)DateTime.Now.Ticks).Next(0, 100000));
            }
    
            listA.AddRange(list);
            Console.WriteLine("" + i + "次比较:{0}...", string.Join(",", list.Take(10)));
    
            Stopwatch watch = new Stopwatch();
            watch.Start();
            InsertSort(list);
            watch.Stop();
            Console.WriteLine("
    直接插入排序耗费时间:" + watch.ElapsedMilliseconds);
            Console.WriteLine("输出前是十个数:" + string.Join(",", list.Take(10).ToList()));
    
            watch.Restart();
            ShellSort(listA);
            watch.Stop();
            Console.WriteLine("
    希尔排序耗费时间:" + watch.ElapsedMilliseconds);
            Console.WriteLine("输出前是十个数:" + string.Join(",", listA.Take(10).ToList()));
        }
    }

    从结果上看, 希尔排序的改进效果还是蛮明显的. 但是希尔排序并不是一个稳定的排序方式. 也就是说, 还是可能出现比快速排序慢的时候.

  • 相关阅读:
    网络信息安全攻防学习平台第7题
    深入理解读写锁ReentrantReadWriteLock
    彻底理解ReentrantLock
    (三)应该了解关于并发相关的概念
    (二)并发编程的优缺点
    Linux Makefile多目录的编写
    libcurl 下载上传
    MFC枚举USB设备碰到的一个疑难,还没解决
    MFC一个令人纠心的错误
    如何为你的App获取用户的反馈和5星级评论
  • 原文地址:https://www.cnblogs.com/elvinle/p/6669258.html
Copyright © 2020-2023  润新知