目录
插入排序
要想理解希尔排序 O(logN * N),首先你必须理解直接插入排序 O(N^2)
直接插入排序思想就是:[0, end] 已经有序,把 end+1 位置的值插入前面,使得 [0,end+1]有序
话不多说上代码,注释详细
#include<stdio.h>
//直接插入排序 O(N^2)
//最坏 ?逆序 1+2+3+...+n-1
//最好 ?顺序 O(N)
void InsertSort(int *arr,int Size)
{
for(int i=0; i<Size-1; i++)
{
//如果下标[0,end]有序,把 end+1 插入后 [0,end+1] 有序
//i<Size-1 即end最后一个位置是Size-2 -> 倒数第二个位置,如果到倒数第一个位置,end+1会越界
int end=i;
int temp=arr[end+1];
while(end >= 0)//最多插入在第一个位置
{
if(arr[end] > temp)//只要插入的值要比前一个小,前一个就往后挪一位
{
arr[end+1]=arr[end];
end--;
}
else
{
break;
}
}
//如果 1.break到这里就是找到比temp小的了 2.while循环走完结束到这里end == -1了
arr[end+1]=temp;
}
}
int main()
{
int arr[]={5,2,1,4,3};
InsertSort(arr,5);
for(int i=0;i<5;i++)
{
printf("%d ",arr[i]);
}
return 0;
}
希尔排序
显然直接插入排序的效率不高,优化后 -> 希尔排序
希尔排序就是把相隔gap距离的分成一组,首先进行预排序,使数组几乎接近有序,这样就可以使插入排序效率大大提高,注意是相隔gap,不是每gap个一组
如下图 例如 gap=3
gap=3,预排序完如下图:
显然这时候再进行直接插入排序效率会更高
在实际中gap不能固定为3,所以每次需要使gap变动(这里方法不唯一,可以gap每次除2),使它和数组Size有关,但最后一次gap必须是1,这样才能使他完全有序。
可以与上面的直接插入排序比较 内部循环 ,就是把上面的1改为了gap,代码如下(详细注释):
#include<stdio.h>
//直接插入排序的优化 -> 希尔排序
//1.先进行预排序(分组排,每间隔gap一组),让数组接近有序(这样可以让直接插入排序效率更高)
//2.直接插入排序 -> O(N)
//时间复杂度O(log3N * N) 或者 O(logN * N)
void SheelSort(int *arr,int Size)
{
int gap=Size;
while(gap > 1)
{
//gap >1 时都是预排序 ->接近有序
//gap==1 时就是直接插入排序 ->完全有序
//或者gap=gap/3 + 1;
gap=gap/2; //除2可以保证最后一次gap==1 -> 变成完全有序
for(int i=0; i<Size-gap; i++)//把间隔为gap的多组数据同时排,最后i == Size-gap-1
{
int end=i;
int temp=arr[end+gap];
while(end >= 0)
{
if(arr[end] > temp)
{
arr[end+gap]=arr[end];
end=end-gap;
}
else
{
break;
}
}
arr[end+gap]=temp;
}
}
}
int main()
{
int arr[]={5,2,1,4,3};
SheelSort(arr,5);
for(int i=0;i<5;i++)
{
printf("%d ",arr[i]);
}
return 0;
}