• 排序算法总结


    1插入类排序

    (1)直接插入排序

      算法大致流程:给定初始序列L,L从前往后依次取出一个数据,将其直接插入到有序序列中。

      算法的复杂度分析:时间复杂度:最坏的情况下,每从无序序列中取一个元素,就要遍历一遍有序序列,复杂度为O(n2);最好的情况下,每从无序序列中取出一个元素,直接放在了有序序列的后面,也就是不用遍历有序序列,此时,复杂度为O(n)。所以,平均复杂度为O(n2)。

               空间复杂度:O(1)

     1 #include<cstdio>
     2 #define MAXSIZE 100
     3 void out(int number[],int n)
     4 {
     5     for(int i=0; i<n; ++i)
     6         printf("%d	",number[i]);
     7 }
     8 void InsertSort(int number[],int n)
     9 {
    10     int i,j;
    11     int temp,flag=0;
    12     for(i=1; i<n; ++i)
    13     {
    14         flag=0;
    15         temp=number[i];
    16         for(j=0; j<i; ++j)
    17         {
    18             if(number[i]<number[j])
    19             {
    20                 for(int k=i; k>j; --k)
    21                     number[k]=number[k-1];
    22                 number[j]=temp;
    23                 flag=1;
    24             }
    25             if(flag==1)
    26                 break;
    27         }
    28     }
    29     out(number,n);
    30 }
    31 
    32 int main()
    33 {
    34     int number[MAXSIZE];
    35     int n;
    36     scanf("%d",&n);
    37     for(int i=0; i<n; ++i)
    38         scanf("%d",&number[i]);
    39     InsertSort(number,n);
    40     return 0;
    41 }

    (2)折半插入排序

      算法大致流程:给定初始序列L,L从前往后依次取出一个数据,将其插入到有序序列中,到这里和直接插入排序相同。不同之处就在于,插入到有序序列中时,由于其是有序的,我们就可以采用二分的方式快速找到该元素在有序序列中的位置。

      算法的复杂度分析:时间复杂度:最坏的情况下,每从无序序列中取一个元素,就要遍历n/2个有序序列元素,复杂度为O(n2),最好的情况和直接插入排序一样,也是O(n)。平均复杂度为:O(n2)。

               空间复杂度:O(1)

    (3)希尔排序(缩小增量排序)

      算法大致流程:给定初始序列L,假设下标为0、1、2、3……n,例如,首先以5为增量分割序列,所以,0、5、10、15……为一组;1、6、11、16……为一组;2、7、12、17……为一组,将数列分为5组,这五组序列分别进行排序,构成一趟希尔排序。然后对排序后的整个数列,以3为增量分割序列,所以,0、3、6、9……一组;1、4、7、……一组,2、5、8、……一组,分为3组,对这三组数据分别进行排序,又做了一趟希尔排序。最后直到增量为1,就相当于整个序列作为一组进行一趟排序,从而使最终序列有序。

      注:对于增量的选择,增量序列中没有除1以外的公因子,例如5、3、1就符合,8、4、2、1有公因子2,不符合。

      算法的复杂度分析:时间复杂度:O(nlog2n)

               空间复杂度:O(1)

    2交换类排序

    (1)冒泡排序

      算法大致流程:给定初始序列L(含有n个元素),先用第0个元素和第1个元素比较,如果第0个元素比第1个元素大,则两个元素交换,否则什么都不做,然后第1个元素和2个元素比较,如果第1个元素大,则交换,一直进行下去,直到比较到n-2和n-1,完成一趟冒泡,最大的元素a被就冒上来,放在了正确的位置上(即最大的放在了最后)。然后采用相同的方法完成第二次冒泡,直到比较到n-3和n-2,那么除了a意外的其他所有元素的最大值最终放在了n-2的位置上……最后,只剩2个元素时,比较,交换,算法完成。在一趟冒泡过程中,没有元素交换,也结束算法。

      算法的复杂度分析:时间复杂度:最坏情况下,每次都要交换,复杂度为O(n2),最好的情况是已经有序,复杂度为O(n)。平均复杂度为:O(n2)。

               空间复杂度:O(1)

     1 #include <stdio.h>
     2 
     3 void swap(int *a,int *b)
     4 {
     5     int temp;
     6     temp=*a;
     7     *a=*b;
     8     *b=temp;
     9 }
    10 
    11 int main()
    12 {
    13     int i,j,n;
    14     int number[100000];
    15     scanf("%d",&n);
    16     for(int i=0;i<n;++i)
    17         scanf("%d",&number[i]);
    18     for(i=n-1;i>0;--i)
    19     {
    20         for(j=0;j<i;++j)
    21         {
    22             if(number[j]>number[j+1])
    23             {
    24                 swap(&number[j],&number[j+1]);
    25             }
    26         }
    27     }
    28     for(i=0;i<n;++i)
    29     {
    30         printf("%d ",number[i]);
    31     }
    32     return 0;
    33 }

    (2)快排

      算法的大致流程:给定初始序列L,任意选定某个数作为基准(一般选择序列的第一个数L[0]),从L[1]开始向右依次比较,第一次发现某个数L[k]比基准大的时候,交换L[0]和L[left],此时的位置记为“left=left+1”,然后再开始从右往左查看,L[n-1]、L[n-2]……,当发现第一个比L[0]小的L[right]时候,交换L[0]和L[right],此时记录位置为“right=right+1”,然后从L[left]开始向右看,重复上述过程,直到遇到比L[0]大的元素,记录位置,从L[right]开始向左看……直到left和right相遇,一趟快排完成,此时L[0]左边的元素均比L[0]小,L[0]右边的元素均比L[0]大。L[0]将L分成左右两部分,L和R。

      对L和R分别执行和L一样的操作,直到最后分得的L和R中只有两个元素。

      算法的复杂度分析:时间复杂度:最好的情况下是:O(nlog2n),最坏的情况下是O(n2),待排序列越接近无序,效率越高,越有序,效率越低,排序的趟数和初始序列有关。平均复杂度为O(nlog2n)。

               空间复杂度:需要借助栈,O(log2n)

     1 #include<stdio.h>
     2 int n;
     3 void quick_sort(int number[],int left,int right)
     4 {
     5     int a,b;
     6     int start;
     7     int temp;
     8     if(left>=right)
     9     {
    10         return;
    11     }
    12     temp=left;
    13     a=left;
    14     b=right;
    15     start=number[left];
    16     while(left<right)
    17     {
    18 
    19         while(number[right]>=start&&right>left)
    20         {
    21             right--;
    22         }
    23         number[temp]=number[right];
    24         temp=right;
    25         while(number[left]<=start&&left<right)
    26         {
    27             left++;
    28         }
    29         number[temp]=number[left];
    30         temp=left;
    31     }
    32     number[temp]=start;
    33     quick_sort(number,a,right-1);
    34     quick_sort(number,left+1,b);
    35 }
    36 
    37 int main()
    38 {
    39     int i,j;
    40     int number[100000];
    41     scanf("%d",&n);
    42     for(int i=0;i<n;++i)
    43         scanf("%d",&number[i]);
    44     quick_sort(number,0,n-1);
    45     for(int i=0; i<n; i++)
    46     {
    47         printf("%d ",number[i]);
    48     }
    49     return 0;
    50 }

    3选择类排序

    (1)直接选择

      算法大致流程:给定初始序列L(n个元素),从L中选择最小的值,和第一个元素交换,完成一次选择,此时有序序列的元素个数为1,无序序列的元素个数为n-1。接着对无序序列做相同的操作……直到无序序列个数为0,算法结束。

      算法的复杂度分析:时间复杂度:平均复杂度为O(n2)。

               空间复杂度:O(1)

     1 #include<stdio.h>
     2 void swap(int *a,int *b)
     3 {
     4     int temp;
     5     temp=*a;
     6     *a=*b;
     7     *b=temp;
     8 }
     9 
    10 int main()
    11 {
    12     int i,j,n;
    13     int number[1000];
    14     int point;
    15     scanf("%d",&n);
    16     for(i=0;i<n;i++)
    17     {
    18         scanf("%d",&number[i]);
    19     }
    20 
    21     for(i=0;i<n;i++)
    22     {
    23         int min=100000;
    24         for(j=i;j<n;j++)
    25         {
    26             if(number[j]<=min)
    27             {
    28                 min=number[j];
    29                 point=j;
    30             }
    31         }
    32         swap(&number[point],&number[i]);
    33     }
    34 
    35     for(i=0;i<n;i++)
    36     {
    37         printf("%d ",number[i]);
    38     }
    39     return 0;
    40 }

    (2)堆排序

      堆:可看做一棵完全二叉树,对于每个非叶节点,满足父亲比孩子小(最小堆)或者父亲比孩子大(最大堆)。

      算法大致流程:首先,用初始序列构建一棵完全二叉树,从最后一个非叶节点往前依次调整——比较他和它两个孩子的大小关系,若比两个孩子小,则将该父节点和两个孩子中较大的交换,即构建最大堆。

      建立好最大堆时,第一趟排序完成,此时堆顶元素为最大元素,将他和最后一个元素交换,剩下的元素还是一棵完全二叉树,但是可能不满足堆的定义,将其重新构建为最大堆,(此时不满足最大堆的元素只有交换的那个值,所以,只需要调整那个值就可以了),将堆顶元素和最后一个元素交换,将剩下的元素构建最大堆,直到剩余元素只有1个,算法结束。

      算法的复杂度分析:时间复杂度:最好和最坏的情况下复杂度均为O(nlog2n)。

               空间复杂度:O(1)

    4归并排序

    二路归并排序

      算法的大致流程:首先将初始序列L中每个元素作为一组,共分为n组。n组中相邻的两两归并,形成n/2(向上取整)组,将这些组内的元素进行排序,然后将这n/2(向上取整)组元素再两两归并,形成n/4(向上取整)组,将组内元素排序……重复这个操作,直到n/2k=1,即最后归并为整个序列L,使之有序,算法结束。

      算法的复杂度分析:时间复杂度:和初始序列无关,最好和最坏的情况下复杂度均为O(nlog2n)。

               空间复杂度:需要转存序列,空间复杂度为O(n)

    5基数排序

      算法大致流程:基数排序就是按多个关键字进行排序,这里举两个栗子:

      1、扑克牌(除大小王)排序:按照两个关键字:花色和数字。先按花色将牌分为4堆,然后将这4堆牌分别按照数字大小排序,最终使整副牌有序。

      2、数字排序:按照低位优先的顺序,分别进行“分配”和“收集”操作,从低位到高位所有位都比完之后,算法完成,整个序列有序。

      例如:对278、109、063、930、589、184、505、269、008、083进行基数排序。

      首先,纵观全部的数字,0~9都有,那么我们就设置10和桶来接收这些位。

      (1)先从最低位(个位)开始,即按照个位数进行分配,其余先不管,分配结果如下:

    0 1 2 3 4 5 6 7 8 9
     元素  930    

    063

    083

     184  505    

    278

    008 

    109

    589

    269

      收集的时候,每个桶看成队列,执行“先进先出”,所以收集结果为“930、063、083、184、505、278、008、109、589、269”

      (2)按照十位分配,结果如下:

    0 1 2 3 4 5 6 7 8 9
    元素

    505

    008

    109

        930    

    063

    269

    278

    083

    184

    589

     

      收集:“505、008、109、930、063、269、278、083、184、589”

      (3)按照百位进行分配,结果如下:

    0 1 2 3 4 5 6 7 8 9
    元素

    008

    063

    083

    109

    184

    269

    278

       

    505

    589

          930

       收集结果:“008、063、083、109、184、269、278、505、589、930”

      至此,所有的位都比较完,算法结束,可见,最后的序列就是从小到大有序的。

      该算法的思想就是,每次比较某一位时,“分配”的目的是保证下一位小的在前面,“收集”的目的是保证,该为小的在前面,这样,所有的收集分配结束后,小的在前面,大的在后面。

      算法的复杂度分析:时间复杂度:平均和最坏的情况下复杂度均为O(d*(n+rd))。其中,d为关键字位数,栗子中d=3。n为元素数,栗子中,n=10。rd关键字取值范围,栗子中rd=10(即0~9)。

               空间复杂度:需要rd个桶,空间复杂度为O(rd)。

  • 相关阅读:
    GIT 旧库迁移到新库
    Spring Data JPA入门
    (一)《Spring实战》——Spring核心
    easyui框架Date日期类型以json形式显示到前台datagrid时,显示为[object Object]
    《小狗钱钱》笔记——脑图
    ORACLE 两个表或两个结果集的数据对比常用的函数
    SyntaxError: Non-ASCII character 'xe5' in file index.py on line 6, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
    报表查询:收费汇总表
    项目启动时 Exception in thread "HouseKeeper" java.lang.NullPointerException
    eval函数处理JSON数据需要加括号
  • 原文地址:https://www.cnblogs.com/wktwj/p/4914718.html
Copyright © 2020-2023  润新知