首页 > 编程语言 >常见的排序算法——希尔排序

常见的排序算法——希尔排序

时间:2024-04-16 11:14:18浏览次数:27  
标签:... int 算法 希尔 time cpp 排序

本文记述了希尔排序的基本思想和一份参考实现代码,并在说明了算法的性能后用随机数据进行了验证。

◆ 思想

给定元素之间的间隔 h ,将所有间隔为 h 的元素作为独立的待排序范围,可以得到 h 个这样的子范围。针对每个子范围执行插入排序,使得任意间隔为 h 的元素是有序的。然后缩小间距 h,对新的子范围重复以上的插入排序,直到间隔 h 递减至 1 为止(间距 h 的计算基于理论研究)。如要得到逆序的结果,则仅需改变比较的方向即可。

◆ 实现

排序代码采用《算法(第4版)》的“排序算法类模板”实现。(代码中涉及的基础类,如 Array,请参考算法文章中涉及的若干基础类的主要API

// shell.hxx

...

class Shell
{

    ...

    template
    <
        class _T,
        class = typename std::enable_if<std::is_base_of<Comparable<_T>, _T>::value>::type
    >
    static
    void
    sort(Array<_T> & a)
    {
        int N = a.size();
        int h = 1;
        while (h < N/3) h = 3*h + 1;            // #1
        while (h >= 1) {
            for (int i = h; i < N; ++i) {      // #2
                _T t = a[i];
                int j;
                for (j = i; j >= h && __less__(t, a[j-h]); j -= h)
                    a[j] = a[j-h];
                a[j] = t;
            }
            h /= 3;         // #1
        }
    }
    
    ...
    
    template
    <
        class _T,
        class = typename std::enable_if<std::is_base_of<Comparable<_T>, _T>::value>::type
    >
    static
    bool
    __less__(_T const& v, _T const& w)
    {
        return v.compare_to(w) < 0;         // #3
    }

    ...

使用简单的公式计算间距(#1)。针对每个子范围执行不需要交换的插入排序(#2)。将 '<' 改为 '>',即得到逆序的结果(#3)。

◆ 性能

时间复杂度 空间复杂度 是否稳定
N^(6/5) ? N^(5/4) ? 1

【注】“透彻理解希尔排序的性能至今仍然是一项挑战。... 算法的性能不仅取决于 h,还取决于 h 之间的数学性质,...”(引《算法(第4版)》)。

◆ 验证

测试代码采用《算法(第4版)》的倍率实验方案,用随机数据验证其正确性并获取时间复杂度数据。

// test.cpp
    
...

time_trial(int N)
{
    Array<Double> a(N);
    for (int i = 0; i < N; ++i) a[i] = Std_Random::random();    // #1
    Stopwatch timer;
    Shell::sort(a);                     // #2
    double time = timer.elapsed_time();
    assert(Shell::is_sorted(a));            // #3
    return time;
}

...

test(char * argv[])
{
    int T = std::stoi(argv[1]);          // #4
    double prev = time_trial(512);
    Std_Out::printf("%10s%10s%7s\n", "N", "Time", "Ratio");
    for (int i = 0, N = 1024; i < T; ++i, N += N) {            // #5
        double time = time_trial(N);
        Std_Out::printf("%10d%10.3f%7.1f\n", N, time, time/prev);   // #6
        prev = time;
    }
}

...

用 [0,1) 之间的实数初始化待排序数组(#1),打开计时器后执行排序(#2),确保得到正确的排序结果(#3)。整个测试过程要执行 T 次排序(#4)。每次执行排序的数据规模都会翻倍(#5),并以上一次排序的时间为基础计算倍率(#6),

此测试在实验环境一中完成,

$ g++ -std=c++11 test.cpp std_out.cpp std_random.cpp stopwatch.cpp type_wrappers.cpp

$ ./a.out 8

     N      Time  Ratio
  1024     0.006    3.0
  2048     0.015    2.5
  4096     0.037    2.5
  8192     0.086    2.3
 16384     0.197    2.3
 32768     0.462    2.3
 65536     1.091    2.4
131072     2.549    2.3

可以看出,随着数据规模的成倍增长,排序所花费的时间将是上一次规模的 2.3 倍。将数据反映到以 2 为底数的对数坐标系中,可以得到如下图像,

test_data

O(N^(6/5)) 代表了(6/5)次方级别复杂度下的理论排序时间,该行中的数据是以 Time 行的第一个数据为基数逐一乘 2^(6/5) 后得到的结果(因为做的是倍率实验,所以乘 (2)^(6/5) 即 2.29)。

O(N^(5/4)) 代表了(5/4)次方级别复杂度下的理论排序时间,该行中的数据是以 Time 行的第一个数据为基数逐一乘 2^(5/4) 后得到的结果(因为做的是倍率实验,所以乘 (2)^(5/4) 即 2.37)。

◆ 最后

完整的代码请参考 [gitee] cnblogs/18137029

写作过程中,笔者参考了《算法(第4版)》的希尔排序、“排序算法类模板”和倍率实验。致作者 Sedgwick,Wayne 及译者谢路云。

标签:...,int,算法,希尔,time,cpp,排序
From: https://www.cnblogs.com/green-cnblogs/p/18137029

相关文章

  • 深度学习算法中的稀疏编码(Sparse Coding)
    【摘要】引言稀疏编码(SparseCoding)是深度学习算法中的一种重要技术,它在神经网络模型中发挥着重要的作用。本文将介绍稀疏编码的基本概念、原理以及在深度学习中的应用。稀疏编码的概念稀疏编码是一种通过寻找数据的稀疏表示来描述数据的方法。在深度学习中,稀疏编码可以将输入数......
  • 基于直方图相似性的图像分类算法FPGA实现,包括tb测试文件和MATLAB辅助验证
    1.算法运行效果图预览MATLAB测试结果:    FPGA测试结果:   上述仿真图中,红色XX表示图像读取完毕。因此输出XX。当图像输出完成之后,最下面的相似性指标 same1输出为11226,same2输出为67584.即图1和图2相似性较强,图1和图3相似性较弱。 2.算法运行软件版本vi......
  • 27天【代码随想录算法训练营34期】第七章 回溯算法part03(● 39. 组合总和 ● 40.组合
    39.组合总和怎么才能避免重复?比现在数小的数就别append到path里面了,之前肯定都试过了classSolution:defcombinationSum(self,candidates:List[int],target:int)->List[List[int]]:result=[]candidates.sort()self.backtracking(cand......
  • 算法相关读书笔记
    由于算法导论中涉及大量数学公式,在腾讯文档才能友好的展示,因此下面分享的为腾讯文档的链接个人能力有限,可能有的理解是错误的,请谅解,仅供分享和参考【腾讯文档】算法导论1~3部分【腾讯文档】算法导论第4~5部分【腾讯文档】算法导论第6部分22~24章【腾讯文档】算法导论第6部分2......
  • 合并k个已排序链表
    利用新的ArrayList合并k个链表 遍历提供给我们的数组,依次得到各个头结点。依次遍历每个头结点下的链表,把他们加入新的数组中。利用Collections.sort()方法得到有序的数组最后把这个新的数组转换成链表并返回。publicListNodemergeKLists(ArrayList<ListNode>lists){......
  • element表格自带sortable属性排序错乱问题
       参考:https://blog.csdn.net/qq_40004867/article/details/129835446?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-129835446-blog-126339196.235%5Ev43%5Epc_blog_bottom_relevance_base4&dept......
  • 深入理解DES算法:原理、实现与应用
    title:深入理解DES算法:原理、实现与应用date:2024/4/1421:30:21updated:2024/4/1421:30:21tags:DES加密对称加密分组密码密钥管理S盒P盒安全性分析替代算法DES算法简介历史DES(DataEncryptionStandard)算法是由IBM研发,并于1977年被美国国家标准局(NBS,现NIST......
  • 八大排序算法
    八大排序冒泡排序/*稳定排序时间复杂度:O(n^2)空间复杂度:O(1)*/publicstaticvoidbubbleSort(int[]nums){for(inti=0;i<nums.length-1;i++){booleanflag=false;for(intj=0;j<nums.length......
  • 2XC3 最短路径算法
    计算机科学:最终项目此项目将包括最终报告和您的代码。您的最终报告将包括以下内容。你会正在为此最终项目提交.py(NOT*.ipynb)文件。•标题页•目录•图表表•一份执行摘要,强调你的实验/分析的一些主要收获•向TA解释如何导航代码的附录。对于每个实验,在你的实验室报告中包括一个与......
  • SpringBoot项目中对定义的多个BeanPostProcessor排序
    前言BeanPostProcessor是Spring提供的一种扩展机制,可以让我们在bean初始化前后做一些额外的操作,Spring中的@Async,@Scheduled,@RabbitHandler等注解的底层实现都是BeanPostProcessor在起作用,如RabbitListenerAnnotationBeanPostProcessor。代码示例@Configurationpub......