关于排序算法的分析和思考
插入类排序
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、折半插入排序
课程里是在直接插入排序中讲了 在因为比较类似, 折半查找法的一个基本条件是序列基本有序,使用折半查找法
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
求出mid >55 所以在 mid左边另外,因为 low>hign循环结束
算法性能
时间复杂度分析
折半适合关键字较多的场景,与直接插入排序对比,折半插入排序在查找插入位置上面画的时间大大减少,折半插入排序的移动次数与直接插入一样所以空间复杂度一样 最好情况为 O(nlog2n) 最坏情况 O(n^2) 平均O(n^2)
空间复杂度分析 同直接插入排序相同为O(1)
3、希尔排序
跟散列表的地址法很像 在探测法 和线性探测法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、快速排序
所有排序中性能最屌最优秀的就是快速排序
需要设立一个基准 然后将low 和hign 依次比较 并将其放到合适的位置 hign先移动知道找到 小于49的值然后移动
然后再移动low 直到找到大于49的值 当low == high的时候 就把基准放进去
然后分成两个部分后在形成 一个基准27 和76
快速排序中对每一个子序列的一次划分都算作一趟排序,每一堂技术之后都有关键字到达最终位置
算法性能
时间复杂度
快速排序最好情况下的时间复杂度为O(nlog2n) 待排序列越接近无序,本算法效率越高,
最坏情况是越接近有序越不行 O(n^2) 平均O(nlog2n)
空间复杂度
O(log2n) 本算法用了很多递归
代码
选择类排序
1、简单选择排序
2、堆排序
3、归并排序
把两个 或多个已经有序的序列进行合并一个
将两个序列 同时进行对比
2路归并 把两个或多个已经有序的序列合并成一个
四路归并
m路归并 选出一次关键字 需要m-1次比较
二路归并排序为内部排序主流
归并排序算法
- 若low>hign.则强序列分从中间mid =(low+high)/2
- 对于左部分 [low,mid] 递归的进行归并操作
- 对于右部分[mid+1,height] 递归的进行归并操作
- 将左右边有序子序列merge为一个
算法性能
空间复杂度=O(n) 空间复杂度 = O(nlogn) 具有稳定性 如果两部分 有两个元素相同取左边
4、基数排序
得到关键字递减的有序序列
第一趟以个位进行分配 比较特殊的排序
先分配再收集 分递增和递减 基数排序得到递减序列的过程如下
分三趟分配收集 因为 个十百 然后按照大小顺序进行比较
因为出现的数字为 0~9所以 再按照个位数字进行分配 然后从上大下收集 依次完成个十百
基数排序使用链式存储实现
算法性能
因此空间复杂度 为O(r) 有r个辅助队列
是稳定的