关于排序算法的分析和思考

138 阅读3分钟

关于排序算法的分析和思考

插入类排序

image-20230731184027121转存失败,建议直接上传图片文件

1、插入算法 (直接插入排序)

和顺序查找很像每插入一个元素,都要较之前比较一下,最后得到的就是一个有序的顺序表。

在算法的书写上涉及到之前顺序表查找和插入的过程

//直接插入排序

#include <stdio.h>
void  InsertSort(int A[],int n)
{
    int i,j,temp;
    for( i=1;i<n;i++)
    {
        if(A[i]<A[i-1])
        {
          temp = A[i];
          for( j=i-1;j>=0&&A[j]>temp;--j)//j在i前一位 j不能等于0 A[j]>temp;j--
          {
               A[j+1]=A[j];
          }
          A[j+1]=temp;
        }
    }
}
int main()
{
    int B[] = {9, 5, 1, 4, 8, 2, 7, 3, 6};
    int n = sizeof(B) / sizeof(B[0]);  //该数组的长度
    printf("before Sorting:\n");
    for( int i=0;i<n;i++)
    {
         printf("%d",B[i]);
    }
    InsertSort(B,n);
    printf("\nafter Sorting:\n");
    for( int i=0;i<n;i++)
    {
        printf("%d",B[i]);
    }
    return 0;
}

算法性能

时间复杂度分析

最坏情况 全部都是逆序 O(n^2)

最好情况 是已经是有序的 O(n)

空间复杂度分析

算法所需要的辅助空间不会因为规模变化而变化 所以始终是O(1)

考点

插入类排序的特点:一趟排序不一定会让关键字到达最终位置,因为在最后一趟前没有一个关键字到达最终位置

2、折半插入排序

课程里是在直接插入排序中讲了 在因为比较类似, 折半查找法的一个基本条件是序列基本有序,使用折半查找法

image-20230731184424933转存失败,建议直接上传图片文件

low =1 high =7 mid = ((low+high)/2)向下取整 =4 下表为四的值为50 55>50,所以 high不变 low =mid+1

low =5 high =7 mid =6 值为70 55<70 所以插入的位置在6的左边, hign =mid-1;

即 low =5, high =5

image-20230731185723749转存失败,建议直接上传图片文件

求出mid >55 所以在 mid左边另外,因为 low>hign循环结束

image-20230731190052884转存失败,建议直接上传图片文件

算法性能

时间复杂度分析

折半适合关键字较多的场景,与直接插入排序对比,折半插入排序在查找插入位置上面画的时间大大减少,折半插入排序的移动次数与直接插入一样所以空间复杂度一样 最好情况为 O(nlog2n) 最坏情况 O(n^2) 平均O(n^2)

空间复杂度分析 同直接插入排序相同为O(1)

3、希尔排序

image-20230731164735676转存失败,建议直接上传图片文件

跟散列表的地址法很像 在探测法 和线性探测法H()+d 每次 d =n/2 每次减半 直到d =1;

希尔的算法实现与逻辑并不一样

步骤为 d1 = n/2 所以,i= d1+1 然后比较的是A[i]<A[i-d1] 如果满足条件就将 A[i]放入A[0]作为暂存值接着for循环比较

i-=d1; 然后进行调换 将A[0]的值放到A [j+d];

算法性能

希尔排序并不稳定,

时间复杂度分析 shell 每次增量都是n/2并向下取整,此时是时间复杂度为O(n^2);

空间复杂度分析 同直接插入排序相同为O(1)

考点

最后一趟时,增量一定为1

增量序列中的值应尽量没有除1以外的公因子

交换类排序

1、冒泡排序

从后往前两两比较相邻元素的值,若为逆序(即A[i-1]>A[i]),则交换他们,直到序列比较完,称炸药那个过程为一趟冒泡排序 总共需要 n-1趟 每两个元素之间比较一次

若某一趟排序没有发生"交换" 说明已经整体有序 只有A[j-1]<A[j]才能交换

所以

算法性能

具有稳定性

时间复杂度

最坏情况下,若序列为逆序,则复杂度为O(n^2);

最好情况下,排列有序,内部只需要进行n-1次后就能整个算法结束 可见时间复杂度为O(n)

综合来看时间复杂度为O(n^2);

空间复杂度 为辅助空间只有一个temp 所以复杂度为 O(1)

2、快速排序

所有排序中性能最屌最优秀的就是快速排序

image-20230731210338124转存失败,建议直接上传图片文件

需要设立一个基准 然后将low 和hign 依次比较 并将其放到合适的位置 hign先移动知道找到 小于49的值然后移动

然后再移动low 直到找到大于49的值 当low == high的时候 就把基准放进去

image-20230731210543031转存失败,建议直接上传图片文件然后分成两个部分后在形成 一个基准27 和76

image-20230731210918054转存失败,建议直接上传图片文件

image-20230731210737956转存失败,建议直接上传图片文件

快速排序中对每一个子序列的一次划分都算作一趟排序,每一堂技术之后都有关键字到达最终位置

算法性能

时间复杂度

快速排序最好情况下的时间复杂度为O(nlog2n) 待排序列越接近无序,本算法效率越高,

最坏情况是越接近有序越不行 O(n^2) 平均O(nlog2n)

空间复杂度

O(log2n) 本算法用了很多递归

代码

选择类排序

1、简单选择排序

2、堆排序

3、归并排序

把两个 或多个已经有序的序列进行合并一个

将两个序列 同时进行对比 image-20230801152253634转存失败,建议直接上传图片文件

2路归并 把两个或多个已经有序的序列合并成一个

四路归并

image-20230801152521440转存失败,建议直接上传图片文件

m路归并 选出一次关键字 需要m-1次比较

二路归并排序为内部排序主流

归并排序算法

  1. 若low>hign.则强序列分从中间mid =(low+high)/2
  2. 对于左部分 [low,mid] 递归的进行归并操作
  3. 对于右部分[mid+1,height] 递归的进行归并操作
  4. 将左右边有序子序列merge为一个

算法性能

空间复杂度=O(n) 空间复杂度 = O(nlogn) 具有稳定性 如果两部分 有两个元素相同取左边

4、基数排序

得到关键字递减的有序序列

第一趟以个位进行分配 比较特殊的排序

image-20230801161958650转存失败,建议直接上传图片文件

先分配再收集 分递增和递减 基数排序得到递减序列的过程如下

分三趟分配收集 因为 个十百 然后按照大小顺序进行比较

因为出现的数字为 0~9所以 再按照个位数字进行分配 然后从上大下收集 依次完成个十百

image-20230801164012513转存失败,建议直接上传图片文件

基数排序使用链式存储实现

算法性能

因此空间复杂度 为O(r) 有r个辅助队列

是稳定的