HOME 首页
SERVICE 服务产品
XINMEITI 新媒体代运营
CASE 服务案例
NEWS 热点资讯
ABOUT 关于我们
CONTACT 联系我们
创意岭
让品牌有温度、有情感
专注品牌策划15年

    各种排序算法的比较(各种排序算法的比较和特点)

    发布时间:2023-04-14 00:58:30     稿源: 创意岭    阅读: 109        

    大家好!今天让创意岭的小编来大家介绍下关于各种排序算法的比较的问题,以下是小编对此问题的归纳整理,让我们一起来看看吧。

    开始之前先推荐一个非常厉害的Ai人工智能工具,一键生成原创文章、方案、文案、工作计划、工作报告、论文、代码、作文、做题和对话答疑等等

    只需要输入关键词,就能返回你想要的内容,越精准,写出的就越详细,有微信小程序端、在线网页版、PC客户端

    官网:https://ai.de1919.com

    创意岭作为行业内优秀的企业,服务客户遍布全球各地,如需了解SEO相关业务请拨打电话175-8598-2043,或添加微信:1454722008

    本文目录:

    各种排序算法的比较(各种排序算法的比较和特点)

    一、哪些排序法是基于比较排序法?

    几种常见的基于比较的排序算法:

    1. 选择排序

    2. 冒泡排序

    3. 插入排序

    4. 希尔排序

    5. 归并排序

    6. 快速排序

    7. 堆排序

    8. 二叉排序树排序

    二、常用的数据排序算法有哪些,各有什么特点?举例结合一种排序算法并应用数组进行数据排序。

    排序简介

    排序是数据处理中经常使用的一种重要运算,在计算机及其应用系统中,花费在排序上的时间在系统运行时间中占有很大比重;并且排序本身对推动算法分析的发展也起很大作用。目前已有上百种排序方法,但尚未有一个最理想的尽如人意的方法,本章介绍常用的如下排序方法,并对它们进行分析和比较。

    1、插入排序(直接插入排序、折半插入排序、希尔排序);

    2、交换排序(起泡排序、快速排序);

    3、选择排序(直接选择排序、堆排序);

    4、归并排序;

    5、基数排序;

    学习重点

    1、掌握排序的基本概念和各种排序方法的特点,并能加以灵活应用;

    2、掌握插入排序(直接插入排序、折半插入排序、希尔排序)、交换排序(起泡排序、快速排序)、选择排序(直接选择排序、堆排序)、二路归并排序的方法及其性能分析方法;

    3、了解基数排序方法及其性能分析方法。

    排序(sort)或分类

     所谓排序,就是要整理文件中的记录,使之按关键字递增(或递减)次序排列起来。其确切定义如下:

    输入:n个记录R1,R2,…,Rn,其相应的关键字分别为K1,K2,…,Kn。

    输出:Ril,Ri2,…,Rin,使得Ki1≤Ki2≤…≤Kin。(或Ki1≥Ki2≥…≥Kin)。

    1.被排序对象--文件

    被排序的对象--文件由一组记录组成。

    记录则由若干个数据项(或域)组成。其中有一项可用来标识一个记录,称为关键字项。该数据项的值称为关键字(Key)。

    注意:

      在不易产生混淆时,将关键字项简称为关键字。

    2.排序运算的依据--关键字

     用来作排序运算依据的关键字,可以是数字类型,也可以是字符类型。

      关键字的选取应根据问题的要求而定。

    【例】在高考成绩统计中将每个考生作为一个记录。每条记录包含准考证号、姓名、各科的分数和总分数等项内容。若要惟一地标识一个考生的记录,则必须用"准考证号"作为关键字。若要按照考生的总分数排名次,则需用"总分数"作为关键字。

    排序的稳定性

      当待排序记录的关键字均不相同时,排序结果是惟一的,否则排序结果不唯一。

     在待排序的文件中,若存在多个关键字相同的记录,经过排序后这些具有相同关键字的记录之间的相对次序保持不变,该排序方法是稳定的;若具有相同关键字的记录之间的相对次序发生变化,则称这种排序方法是不稳定的。

    注意:

      排序算法的稳定性是针对所有输入实例而言的。即在所有可能的输入实例中,只要有一个实例使得算法不满足稳定性要求,则该排序算法就是不稳定的。

    排序方法的分类

    1.按是否涉及数据的内、外存交换分

     在排序过程中,若整个文件都是放在内存中处理,排序时不涉及数据的内、外存交换,则称之为内部排序(简称内排序);反之,若排序过程中要进行数据的内、外存交换,则称之为外部排序。

    注意:

      ① 内排序适用于记录个数不很多的小文件

     ② 外排序则适用于记录个数太多,不能一次将其全部记录放人内存的大文件。

    2.按策略划分内部排序方法

     可以分为五类:插入排序、选择排序、交换排序、归并排序和分配排序。

    排序算法分析

    1.排序算法的基本操作

     大多数排序算法都有两个基本的操作:

    (1) 比较两个关键字的大小;

    (2) 改变指向记录的指针或移动记录本身。

    注意:

      第(2)种基本操作的实现依赖于待排序记录的存储方式。

    2.待排文件的常用存储方式

    (1) 以顺序表(或直接用向量)作为存储结构

    排序过程:对记录本身进行物理重排(即通过关键字之间的比较判定,将记录移到合适的位置)

    (2) 以链表作为存储结构

    排序过程:无须移动记录,仅需修改指针。通常将这类排序称为链表(或链式)排序;

    (3) 用顺序的方式存储待排序的记录,但同时建立一个辅助表(如包括关键字和指向记录位置的指针组成的索引表)

    排序过程:只需对辅助表的表目进行物理重排(即只移动辅助表的表目,而不移动记录本身)。适用于难于在链表上实现,仍需避免排序过程中移动记录的排序方法。

    3.排序算法性能评价

    (1) 评价排序算法好坏的标准

    评价排序算法好坏的标准主要有两条:

     ① 执行时间和所需的辅助空间

     ② 算法本身的复杂程度

    (2) 排序算法的空间复杂度

    若排序算法所需的辅助空间并不依赖于问题的规模n,即辅助空间是O(1),则称之为就地排序(In-PlaceSou)。

    非就地排序一般要求的辅助空间为O(n)。

    (3) 排序算法的时间开销

    大多数排序算法的时间开销主要是关键字之间的比较和记录的移动。有的排序算法其执行时间不仅依赖于问题的规模,还取决于输入实例中数据的状态。

    文件的顺序存储结构表示

    #define n l00 //假设的文件长度,即待排序的记录数目

    typedef int KeyType; //假设的关键字类型

    typedef struct{ //记录类型

    KeyType key; //关键字项

    InfoType otherinfo;//其它数据项,类型InfoType依赖于具体应用而定义

    }RecType;

    typedef RecType SeqList[n+1];//SeqList为顺序表类型,表中第0个单元一般用作哨兵

    注意:

     若关键字类型没有比较算符,则可事先定义宏或函数来表示比较运算。

    【例】关键字为字符串时,可定义宏"#define LT(a,b)(Stromp((a),(b))<0)"。那么算法中"a<b"可用"LT(a,b)"取代。若使用C++,则定义重载的算符"<"更为方便。

    按平均时间将排序分为四类:

    (1)平方阶(O(n2))排序

     一般称为简单排序,例如直接插入、直接选择和冒泡排序;

    (2)线性对数阶(O(nlgn))排序

     如快速、堆和归并排序;

    (3)O(n1+£)阶排序

     £是介于0和1之间的常数,即0<£<1,如希尔排序;

    (4)线性阶(O(n))排序

     如桶、箱和基数排序。

    各种排序方法比较

    简单排序中直接插入最好,快速排序最快,当文件为正序时,直接插入和冒泡均最佳。

    影响排序效果的因素

     因为不同的排序方法适应不同的应用环境和要求,所以选择合适的排序方法应综合考虑下列因素:

    ①待排序的记录数目n;

    ②记录的大小(规模);

    ③关键字的结构及其初始状态;

    ④对稳定性的要求;

    ⑤语言工具的条件;

    ⑥存储结构;

    ⑦时间和辅助空间复杂度等。

    不同条件下,排序方法的选择

    (1)若n较小(如n≤50),可采用直接插入或直接选择排序。

     当记录规模较小时,直接插入排序较好;否则因为直接选择移动的记录数少于直接插人,应选直接选择排序为宜。

    (2)若文件初始状态基本有序(指正序),则应选用直接插人、冒泡或随机的快速排序为宜;

    (3)若n较大,则应采用时间复杂度为O(nlgn)的排序方法:快速排序、堆排序或归并排序。

     快速排序是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;

     堆排序所需的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况。这两种排序都是不稳定的。

     若要求排序稳定,则可选用归并排序。但本章介绍的从单个记录起进行两两归并的 排序算法并不值得提倡,通常可以将它和直接插入排序结合在一起使用。先利用直接插入排序求得较长的有序子文件,然后再两两归并之。因为直接插入排序是稳定的,所以改进后的归并排序仍是稳定的。

    4)在基于比较的排序方法中,每次比较两个关键字的大小之后,仅仅出现两种可能的转移,因此可以用一棵二叉树来描述比较判定过程。

     当文件的n个关键字随机分布时,任何借助于"比较"的排序算法,至少需要O(nlgn)的时间。

     箱排序和基数排序只需一步就会引起m种可能的转移,即把一个记录装入m个箱子之一,因此在一般情况下,箱排序和基数排序可能在O(n)时间内完成对n个记录的排序。但是,箱排序和基数排序只适用于像字符串和整数这类有明显结构特征的关键字,而当关键字的取值范围属于某个无穷集合(例如实数型关键字)时,无法使用箱排序和基数排序,这时只有借助于"比较"的方法来排序。

     若n很大,记录的关键字位数较少且可以分解时,采用基数排序较好。虽然桶排序对关键字的结构无要求,但它也只有在关键字是随机分布时才能使平均时间达到线性阶,否则为平方阶。同时要注意,箱、桶、基数这三种分配排序均假定了关键字若为数字时,则其值均是非负的,否则将其映射到箱(桶)号时,又要增加相应的时间。

    (5)有的语言(如Fortran,Cobol或Basic等)没有提供指针及递归,导致实现归并、快速(它们用递归实现较简单)和基数(使用了指针)等排序算法变得复杂。此时可考虑用其它排序。

    (6)本章给出的排序算法,输人数据均是存储在一个向量中。当记录的规模较大时,为避免耗费大量的时间去移动记录,可以用链表作为存储结构。譬如插入排序、归并排序、基数排序都易于在链表上实现,使之减少记录的移动次数。但有的排序方法,如快速排序和堆排序,在链表上却难于实现,在这种情况下,可以提取关键字建立索引表,然后对索引表进行排序。然而更为简单的方法是:引人一个整型向量t作为辅助表,排序前令t[i]=i(0≤i<n),若排序算法中要求交换R[i]和R[j],则只需交换t[i]和t[j]即可;排序结束后,向量t就指示了记录之间的顺序关系:

    R[t[0]].key≤R[t[1]].key≤…≤R[t[n-1]].key

    若要求最终结果是:

    R[0].key≤R[1].key≤…≤R[n-1].key

    则可以在排序结束后,再按辅助表所规定的次序重排各记录,完成这种重排的时间是O(n)。

    三、用代码实现几种排序算法的时间复杂度比较

    一、简单排序算法

    由于程序比较简单,所以没有加什么注释。所有的程序都给出了完整的运行代码,并在我的VC环境

    下运行通过。因为没有涉及MFC和WINDOWS的内容,所以在BORLAND C++的平台上应该也不会有什么

    问题的。在代码的后面给出了运行过程示意,希望对理解有帮助。

    1.冒泡法:

    这是最原始,也是众所周知的最慢的算法了。他的名字的由来因为它的工作看来象是冒泡:

    #include <iostream>

    using namespace std;

    void BubbleSort(int * pData, int Count)

    {

    int iTemp;

    for (int i=0; i<Count; i++)

    {

    for (int j=Count-1; j>i; j--)

    {

    if (pData[j]<pData[j-1])

    {

    iTemp = pData[j-1];

    pData[j-1] = pData[j];

    pData[j] = iTemp;

    }

    }

    }

    }

    void main()

    {

    int data[7] = {10,9,8,7,6,5,4};

    BubbleSort(data,7);

    for (int i=0; i<7; i++)

    {

    cout<<data[i]<<" ";

    }

    cout<<endl;

    system("PAUSE");

    }

    倒序(最糟情况)

    第一轮:10,9,8,7->10,9,7,8->10,7,9,8->7,10,9,8(交换3次)

    第二轮:7,10,9,8->7,10,8,9->7,8,10,9(交换2次)

    第一轮:7,8,10,9->7,8,9,10(交换1次)

    循环次数:6次

    交换次数:6次

    其他:

    第一轮:8,10,7,9->8,10,7,9->8,7,10,9->7,8,10,9(交换2次)

    第二轮:7,8,10,9->7,8,10,9->7,8,10,9(交换0次)

    第一轮:7,8,10,9->7,8,9,10(交换1次)

    循环次数:6次

    交换次数:3次

    上面我们给出了程序段,现在我们分析它:这里,影响我们算法性能的主要部分是循环和交换,

    显然,次数越多,性能就越差。从上面的程序我们可以看出循环的次数是固定的,为1+2+...+n-1。

    写成公式就是1/2*(n-1)*n。

    现在注意,我们给出O方法的定义:

    若存在一常量K和起点n0,使当n>=n0时,有f(n)<=K*g(n),则f(n) = O(g(n))。(呵呵,不要说没学好数学呀,对于编程数学是非常重要的!!!)

    现在我们来看1/2*(n-1)*n,当K=1/2,n0=1,g(n)=n*n时,1/2*(n-1)*n<=1/2*n*n=K*g(n)。所以f(n)

    =O(g(n))=O(n*n)。所以我们程序循环的复杂度为O(n*n)。

    再看交换。从程序后面所跟的表可以看到,两种情况的循环相同,交换不同。其实交换本身同数据源的

    有序程度有极大的关系,当数据处于倒序的情况时,交换次数同循环一样(每次循环判断都会交换),

    复杂度为O(n*n)。当数据为正序,将不会有交换。复杂度为O(0)。乱序时处于中间状态。正是由于这样的

    原因,我们通常都是通过循环次数来对比算法。

    2.交换法:

    交换法的程序最清晰简单,每次用当前的元素一一的同其后的元素比较并交换。

    #include <iostream.h>

    void ExchangeSort(int* pData,int Count)

    {

    int iTemp;

    for(int i=0;i<Count-1;i++)

    { //共(count-1)轮,每轮得到一个最小值

    for(int j=i+1;j<Count;j++)

    { //每次从剩下的数字中寻找最小值,于当前最小值相比,如果小则交换

    if(pData[j]9,10,8,7->8,10,9,7->7,10,9,8(交换3次)

    第二轮:7,10,9,8->7,9,10,8->7,8,10,9(交换2次)

    第一轮:7,8,10,9->7,8,9,10(交换1次)

    循环次数:6次

    交换次数:6次

    其他:

    第一轮:8,10,7,9->8,10,7,9->7,10,8,9->7,10,8,9(交换1次)

    第二轮:7,10,8,9->7,8,10,9->7,8,10,9(交换1次)

    第一轮:7,8,10,9->7,8,9,10(交换1次)

    循环次数:6次

    交换次数:3次

    从运行的表格来看,交换几乎和冒泡一样糟。事实确实如此。循环次数和冒泡一样

    也是1/2*(n-1)*n,所以算法的复杂度仍然是O(n*n)。由于我们无法给出所有的情况,所以

    只能直接告诉大家他们在交换上面也是一样的糟糕(在某些情况下稍好,在某些情况下稍差)。

    3.选择法:

    现在我们终于可以看到一点希望:选择法,这种方法提高了一点性能(某些情况下)

    这种方法类似我们人为的排序习惯:从数据中选择最小的同第一个值交换,在从省下的部分中

    选择最小的与第二个交换,这样往复下去。

    #include <iostream.h>

    void SelectSort(int* pData,int Count)

    {

    int iTemp;

    int iPos;

    for(int i=0;i<Count-1;i++)

    {

    iTemp = pData;

    iPos = i;

    for(int j=i+1;j<Count;j++)

    {

    if(pData[j]<iTemp)

    {

    iTemp = pData[j];

    iPos = j;

    }

    }

    pData[iPos] = pData;

    pData = iTemp;

    }

    }

    void main()

    {

    int data[] = {10,9,8,7,6,5,4};

    SelectSort(data,7);

    for (int i=0;i<7;i++)

    cout<<data<<" ";

    cout<<"\n";

    }

    倒序(最糟情况)

    第一轮:10,9,8,7->(iTemp=9)10,9,8,7->(iTemp=8)10,9,8,7->(iTemp=7)7,9,8,10(交换1次)

    第二轮:7,9,8,10->7,9,8,10(iTemp=8)->(iTemp=8)7,8,9,10(交换1次)

    第一轮:7,8,9,10->(iTemp=9)7,8,9,10(交换0次)

    循环次数:6次

    交换次数:2次

    其他:

    第一轮:8,10,7,9->(iTemp=8)8,10,7,9->(iTemp=7)8,10,7,9->(iTemp=7)7,10,8,9(交换1次)

    第二轮:7,10,8,9->(iTemp=8)7,10,8,9->(iTemp=8)7,8,10,9(交换1次)

    第一轮:7,8,10,9->(iTemp=9)7,8,9,10(交换1次)

    循环次数:6次

    交换次数:3次

    遗憾的是算法需要的循环次数依然是1/2*(n-1)*n。所以算法复杂度为O(n*n)。

    我们来看他的交换。由于每次外层循环只产生一次交换(只有一个最小值)。所以f(n)<=n

    所以我们有f(n)=O(n)。所以,在数据较乱的时候,可以减少一定的交换次数。

    4.插入法:

    插入法较为复杂,它的基本工作原理是抽出牌,在前面的牌中寻找相应的位置插入,然后继续下一张

    #include <iostream.h>

    void InsertSort(int* pData,int Count)

    {

    int iTemp;

    int iPos;

    for(int i=1;i<Count;i++)

    {

    iTemp = pData[i]; //保存要插入的数

    iPos = i-1; //被插入的数组数字个数

    while((iPos>=0) && (iTemp9,10,8,7(交换1次)(循环1次)

    第二轮:9,10,8,7->8,9,10,7(交换1次)(循环2次)

    第一轮:8,9,10,7->7,8,9,10(交换1次)(循环3次)

    循环次数:6次

    交换次数:3次

    其他:

    第一轮:8,10,7,9->8,10,7,9(交换0次)(循环1次)

    第二轮:8,10,7,9->7,8,10,9(交换1次)(循环2次)

    第一轮:7,8,10,9->7,8,9,10(交换1次)(循环1次)

    循环次数:4次

    交换次数:2次

    上面结尾的行为分析事实上造成了一种假象,让我们认为这种算法是简单算法中最好的,其实不是,

    因为其循环次数虽然并不固定,我们仍可以使用O方法。从上面的结果可以看出,循环的次数f(n)<=

    1/2*n*(n-1)<=1/2*n*n。所以其复杂度仍为O(n*n)(这里说明一下,其实如果不是为了展示这些简单

    排序的不同,交换次数仍然可以这样推导)。现在看交换,从外观上看,交换次数是O(n)(推导类似

    选择法),但我们每次要进行与内层循环相同次数的‘=’操作。正常的一次交换我们需要三次‘=’

    而这里显然多了一些,所以我们浪费了时间。

    最终,我个人认为,在简单排序算法中,选择法是最好的。

    二、高级排序算法

    高级排序算法中我们将只介绍这一种,同时也是目前我所知道(我看过的资料中)的最快的。

    它的工作看起来仍然象一个二叉树。首先我们选择一个中间值middle程序中我们使用数组中间值,然后

    把比它小的放在左边,大的放在右边(具体的实现是从两边找,找到一对后交换)。然后对两边分别使

    用这个过程(最容易的方法——递归)。

    1.快速排序:

    #include <iostream.h>

    void run(int* pData,int left,int right)

    {

    int i,j;

    int middle,iTemp;

    i = left;

    j = right;

    middle = pData[left];

    do{

    while((pData[i]<middle) && (i<right))//从左扫描大于中值的数

    i++; 

    while((pData[j]>middle) && (j>left))//从右扫描大于中值的数

    j--;

    if(i<=j)//找到了一对值

    {

    //交换

    iTemp = pData[i];

    pData[i] = pData[j];

    pData[j] = iTemp;

    i++;

    j--;

    }

    }while(i<=j);//如果两边扫描的下标交错,就停止(完成一次)

    //当左边部分有值(left<j),递归左半边

    if(left<j)

    run(pData,left,j);

    //当右边部分有值(right>i),递归右半边

    if(right>i)

    run(pData,i,right);

    }

    void QuickSort(int* pData,int Count)

    {

    run(pData,0,Count-1);

    }

    void main()

    {

    int data[] = {10,9,8,7,6,5,4};

    QuickSort(data,7);

    for (int i=0;i<7;i++)

    cout<<data<<" ";

    cout<<"\n";

    }

    这里我没有给出行为的分析,因为这个很简单,我们直接来分析算法:首先我们考虑最理想的情况

    1.数组的大小是2的幂,这样分下去始终可以被2整除。假设为2的k次方,即k=log2(n)。

    2.每次我们选择的值刚好是中间值,这样,数组才可以被等分。

    第一层递归,循环n次,第二层循环2*(n/2)......

    所以共有n+2(n/2)+4(n/4)+...+n*(n/n) = n+n+n+...+n=k*n=log2(n)*n

    所以算法复杂度为O(log2(n)*n)

    其他的情况只会比这种情况差,最差的情况是每次选择到的middle都是最小值或最大值,那么他将变

    成交换法(由于使用了递归,情况更糟)。但是你认为这种情况发生的几率有多大??呵呵,你完全

    不必担心这个问题。实践证明,大多数的情况,快速排序总是最好的。

    如果你担心这个问题,你可以使用堆排序,这是一种稳定的O(log2(n)*n)算法,但是通常情况下速度要慢

    四、数据结构中各种排序的时间复杂度与空间复杂度比较!

    冒泡排序是稳定的,算法时间复杂度是O(n ^2)。 2.2 选择排序(Selection Sort) 选择排序的基本思想是对待排序的记录序列进行n-1遍的处理,第i遍处理是将L[i..n]中最小者与L[i]交换位置。这样,经过i遍处理之后,前i个记录的位置已经是正确的了。 选择排序是不稳定的,算法复杂度是O(n ^2 )。 2.3 插入排序 (Insertion Sort) 插入排序的基本思想是,经过i-1遍处理后,L[1..i-1]己排好序。第i遍处理仅将L[i]插入L[1..i-1]的适当位置,使得L[1..i] 又是排好序的序列。要达到这个目的,我们可以用顺序比较的方法。首先比较L[i]和L[i-1],如果L[i-1]≤ L[i],则L[1..i]已排好序,第i遍处理就结束了;否则交换L[i]与L[i-1]的位置,继续比较L[i-1]和L[i-2],直到找到某一个位置j(1≤j≤i-1),使得L[j] ≤L[j+1]时为止。图1演示了对4个元素进行插入排序的过程,共需要(a),(b),(c)三次插入。 直接插入排序是稳定的,算法时间复杂度是O(n ^2) 。 2.4 堆排序 堆排序是一种树形选择排序,在排序过程中,将A[n]看成是完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系来选择最小的元素。 堆排序是不稳定的,算法时间复杂度O(nlog n)。 2.5 归并排序 设有两个有序(升序)序列存储在同一数组中相邻的位置上,不妨设为A[l..m],A[m+1..h],将它们归并为一个有序数列,并存储在A[l..h]。 其时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlog2n)。 2.6 快速排序 快速排序是对冒泡排序的一种本质改进。它的基本思想是通过一趟扫描后,使得排序序列的长度能大幅度地减少。在冒泡排序中,一次扫描只能确保最大数值的数移到正确位置,而待排序序列的长度可能只减少1。快速排序通过一趟扫描,就能确保某个数(以它为基准点吧)的左边各数都比它小,右边各数都比它大。然后又用同样的方法处理它左右两边的数,直到基准点的左右只有一个元素为止。 快速排序是不稳定的,最理想情况算法时间复杂度O(nlog2n),最坏O(n ^2)。 2.7 希尔排序 在直接插入排序算法中,每次插入一个数,使有序序列只增加1个节点,并且对插入下一个数没有提供任何帮助。如果比较相隔较远距离(称为 增量)的数,使得数移动时能跨过多个元素,则进行一次比较就可能消除多个元素交换。D.L.shell于1959年在以他名字命名的排序算法中实现了这一思想。算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。 希尔排序是不稳定的,其时间复杂度为O(n ^2)。 排序类别 时间复杂度 空间复杂度 稳定 1 插入排序 O(n2) 1 √ 2 希尔排序 O(n2) 1 × 3 冒泡排序 O(n2) 1 √ 4 选择排序 O(n2) 1 × 5 快速排序 O(Nlogn) O(logn) × 6 堆排序 O(Nlogn) 1 × 7 归并排序 O(Nlogn) O(n) √

    0

    顺序查找, O(n) 二分, O(logn)需要排序分块 分块查找? 不知道..英文是什么? 直接插入 O(n^2) 快速排序 最坏情况O(n^2) 平均O(nlogn) 起泡 和插入很像吧 O(n^2) 希尔,O(n^x) 1<x<2 需要比较复杂的分析方法选择 没听过堆排序 最坏情况和平均都是O(nlogn) 其他:归并(merge) O(nlogn) radix() (看怎么来理解n,也可以说O(n)也可以O(nlogn),需要调用稳定的子排序算法) basket O(n) 这两个属于非比较排序。 给予比较操作(> 或< )的排序算法理论最低复杂度是O(nlogn) 证明: 所有可能情况为n! 构造决策树需要n!子节点 <为二分操作,所以树为二叉树,高度为O(logn!)=O(nlogn)

    以上就是关于各种排序算法的比较相关问题的回答。希望能帮到你,如有更多相关问题,您也可以联系我们的客服进行咨询,客服也会为您讲解更多精彩的知识和内容。


    推荐阅读:

    纺织品ce认证(各种纺织品认证)

    C4D入门必备:超全的C4D建模教程,掌握各种建模的方式方法

    抖音各种类型视频占比(抖音视频的类型占比)

    手机画平面图软件app(手机画平面图软件)

    微信企业微信是什么