首页 > 编程语言 >常见的排序算法——插入排序

常见的排序算法——插入排序

时间:2024-04-07 13:56:17浏览次数:14  
标签:... 4.0 int 插入排序 元素 算法 time 排序

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

◆ 思想

将第一个元素之后的所有元素作为待排序范围,将前面的所有元素作为已排序范围。通过一一比较,逐个交换已排序范围内比第二个元素大的所有元素,使第二个元素被插入到了正确的位置。然后将第二个元素之后的所有元素作为新的待排序范围,将前面的所有元素作为已排序范围。重复以上的比较、查找和交换,直至待排序范围中无元素为止。

如要得到逆序的结果,则仅需改变比较的方向即可。

◆ 实现

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

// insertion.hxx

...

class Insertion
{

    ...

    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();
        for (int i = 1; i < N; ++i)                               // #1
            for (int j = i; j > 0 && __less__(a[j], a[j-1]); --j)       // #2
                __exch__(a, j, j-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^2 1

◆ 验证

测试代码采用《算法(第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;
    Insertion::sort(a);                     // #2
    double time = timer.elapsed_time();
    assert(Insertion::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.228    4.1
  2048     0.903    4.0
  4096     3.623    4.0
  8192    14.514    4.0
 16384    58.291    4.0
 32768   233.445    4.0
 65536   929.223    4.0
131072  3693.824    4.0

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

test_data

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

◆ 最后

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

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

标签:...,4.0,int,插入排序,元素,算法,time,排序
From: https://www.cnblogs.com/green-cnblogs/p/18118487

相关文章

  • ACTL5105人工智能算法
    ACTL5105分配到期时间:2024年4月15日星期日下午5点这是一项个人课业。总分为100分,占总分的20%球场标记。工作分配任务作为一名人寿精算师,你的任务是完成以下两项任务。任务I(25分)创建列出Ax、¨Ax、,2Ax、(IA)x和(IA¨)x假设excel文件“A-population-2020”中人群的年利率为5%。(说明:您......
  • 18天【代码随想录算法训练营34期】● 513.找树左下角的值 ● 112. 路径总和 113.路径
    513.找树左下角的值#Definitionforabinarytreenode.#classTreeNode:#def__init__(self,val=0,left=None,right=None):#self.val=val#self.left=left#self.right=rightclassSolution:deffindBottomLeftValue(self......
  • GC算法总结
    1、Java虚拟机规范中规定了对内存的分配,其中程序计数器、本地方法栈、虚拟机栈属于线程私有数据区,Java堆与方法区属于线程共享数据。2、jdk从1.7开始将字符串常量区由方法区(永久代)移动到了Java堆中。3、Java从NIO开始允许直接操纵系统的直接内存,在部分场景中效率很高,因为避免了......
  • MySQL多表联合查询+分组+排序
    DDLCREATETABLE`student`(`id`int(11)NOTNULLAUTO_INCREMENTCOMMENT'学号',`createDate`datetimeDEFAULTNULL,`userName`varchar(20)DEFAULTNULL,`pwd`varchar(36)DEFAULTNULL,`phone`varchar(11)DEFAULTNULL,`age`tinyint(......
  • 代码随想录算法训练营Day13|239滑动窗口最大值 347前k个高频元素
    学习了Carl的视频今日任务 239. 滑动窗口最大值 (一刷至少需要理解思路)之前讲的都是栈的应用,这次该是队列的应用了。本题算比较有难度的,需要自己去构造单调队列,建议先看视频来理解。 题目链接/文章讲解/视频讲解:代码随想录 347.前 K 个高频元素 (一刷至少需要理......
  • 数据结构 第八章(排序算法)【上】
    写在前面:本系列笔记主要以《数据结构(C语言版)》为参考(本章部分图片来源于王道),结合下方视频教程对数据结构的相关知识点进行梳理。所有代码块使用的都是C语言,如有错误欢迎指出。视频链接:第01周a--前言_哔哩哔哩_bilibili基数排序部分的代码参考了一位小伙伴分享的代码,特此说明一......
  • 堆排序算法
    问题描述现有一组数据:23,45,18,11,13,79,72,25,3,17。请使用快速排序算法将它们按照从小到大的顺序排列。算法思想(1)将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;(2)将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;(3)重新调整结构,使其满足堆定义,然后继续......
  • 蓝桥杯 试题 算法训练 拿金币
    问题描述有一个NxN的方格,每一个格子都有一些金币,只要站在格子里就能拿到里面的金币。你站在最左上角的格子里,每次可以从一个格子走到它右边或下边的格子里。请问如何走才能拿到最多的金币。输入格式第一行输入一个正整数n。以下n行描述该方格。金币数保......
  • 单链表的冒泡,选择和快速排序
    单链表的冒泡,选择和快速排序选择排序选择排序的原理是在每一趟遍历时找出所有数据中最小或者最大的那一个值,然后放到开头或者末尾,在链表里面也是同样的道理,在下面的代码当中,遍历了一遍链表之后,我们找出了最大的那个值,然后用头插法插入链表的开头,关键的地方是链表不能查找......
  • c++算法学习笔记 (20) 哈希表
    1.模拟散列表//拉链法#include<bits/stdc++.h>usingnamespacestd;constintN=100003;inth[N];inte[N],ne[N],idx;//存链voidinsert(intx){intk=(x%N+N)%N;//让负数的余数变成正数(若直接加N,则可能溢出)e[idx]=x;ne[idx]......