插入排序&&希尔排序
- 插入排序
- 希尔排序
上一篇博客我给大家伙说了一下子堆排序,之所以我把插入排序和希尔排序放在一起呢,是因为希尔排序实际上用到了插入排序的思想,希望下面的内容能够帮助到大家.
对于插入排序呢,我们可以参考抓牌顺牌,就在一般情况下,我们也不考虑什么组合技,我们就是按照大小排序的话,是不是抓到一张牌我们就要把这张牌插入到合适的位置呢?是不是牌前面的要比它小,后面的要比它大?
插入排序
public void insertSort(int[]arr){
for(int i=1;i<arr.length;i++){
//这里从1开始是默认至少有两张牌的,只有一张牌的话无论怎样都是有序的
int tmp=arr[i];
int j=i-1;
for(;j>=0;j--){
//这里我们敢确保全部走完后一定是有序的是因为,这边是从少部分
//到大多数的排序,根之前的向下调整建立堆有异曲同工之妙
//在移动之前我们已经确认前面的元素是有序的了,那么我们就需要
//找,找一个比要插入牌小的,这样才可以顺理成章地插入
if(arr[j]>tmp){
//我们敢做出只要j元素大于i元素就往后移的原因就是
//我们是从最前面开始排序的,此时前面已经有序,也就是说前面
//的相对位置不需要改变了
arr[j+1]=arr[j];
}else{
//arr[j+1]=tmp;
j比i元素小了,所以我们理应把i元素插入到j后面一位
break;
}
}
arr[j+1]=tmp;
}
}
希尔排序
针对刚才的插入排序,兄弟们有没有发现,最好情况下也就是数据本身就是有序时,时间复杂度应该是O(N)?因为每次以i进入循环时都会break出来,否则就是O(N^2)的时间复杂度,所以当我们数据趋于有序时,使用插入排序理论上是比较快的.
我们的希尔排序正式使用到了这个原理,请看:
此时我们的数组是乱序的,我们就把这个数组分成数组长度组,那么每一组就是一个!对每一组进行插入排序,因为每一组的个数都十分之小,所以宏观上看来,速度也是很快的
第二轮我们把数组分成数组长度一半的组数,再对每一组进行插入排序:
此时此刻每一组内已经有序了,站在整个数组的角度看来,也已经是部分有序,那么我们为什么要大费周折进行跨越式分组呢?
我觉得啊这还是的从宏观上面把握,我也不跟你们细说,我们就抓住一点,是不是现在大的数据已经趋向于数组的后面了?如果是相邻的两个数据进行比较交换的话,换来换去还是局部几个数据在玩!
那么接下来我们组数变一半,数据变两倍继续玩:
我就不给兄弟们演示了,关键就在于最后那一哆嗦,最后一次我们对整体进行插入排序,那又有人要问了,那为什么不直接使用插入排序呢?因为数据越有序,使用插入排序效果才会越好,我们说过希尔排序本身就是对于插入排序的一种优化.我们来看看代码
public void shellSort(int []arr){
int gap=arr.length;
while(gap>1){
shell(arr,gap);
gap=gap/2;
}
shell(arr,1);
//或者
/./while(gap>1){
gap=gap/2;
shell(arr,gap);
}
/./
}
private void shell(int[]arr,int gap){
for(int i=1;i<arr.length;i++){
int j=i-gap;//使用希尔排序时跨度就不再是1了,应该要变成gap
int tmp=arr[i];
for(;j>=0;j-=gap){
if(arr[j]>tmp){
arr[j+gap]=arr[j];
}else{
break;
}
}
arr[j+gap]=tmp;
}
}
好了,希望我的这篇博客能够帮助到对于插入排序和希尔不太清楚的兄弟们!
百年大道,你我共勉!!!