弱化版直接插入
void InsertSort(int*a,int n){ assert(a); int end=n-2; int x; while(end>=0){ //针对的是原本有顺序的,最后一个和x比,然后加入x后恢复有序 if(a[end]>x){ a[end+1]=a[end]; --end; } else { break; } } a[end+1]=x; }
原本是有序,插入x来使数组继续有序
//升级一下,假如说是随机数,怎么来给他变成有序。 //我们需要假设有序,也就是第一个数存在时,认为第一个数有序,然后第二个数是插入,然后。。。到最后(n个数组也就是 end最后n-2,和插入的最后一个n-1来比较插入 void InsertSort(int *a,int n) { assert(a); for(int i=0;i<n-1;i++){ int end=i;//从头开始默认谁开始就是最后一个,也就是最大的,换句话说无时无刻都在插入的过程 while(end>=0){ if(a[end]>x){ // a[end+1]=a[end]; //最好O(N)有顺序,最坏O(N*N) --end; } else{ break; } } }
弱化版希尔排序
gap是分组的意思,也就是分三组,开始只换9和5.把一个大问题慢慢分成小问题
void ShellSort(int*a,int n){ //按gap分组数据进行排,说白了就是预排处理 int gap=3; int end=0; int x=a[gap+end]; while(end>=0){ if(a[end]>x){ a[end+gap]=a[end]; end-=gap; } else { break; } a[end+gap]=x; } } }
假如是分三组,就是将
较弱版希尔排序,简单的排一组
void ShellSort(int*a,int n){ //按gap分组数据进行排,说白了就是预排处理 int gap=3; for(int i=0;i<n-gap;i+=gap) //加了一个这个,简单排一组的黑线, int end=i; int x=gap+end; //为什么是n-gap看下面 while(end>=0){ if(a[end]>x){ a[end+gap]=a[end]; end-=gap; } else { break; } a[end+gap]=x; } } }
为什么要在n-gap : 首先i=0;,n-gap就是上面的6,6的前面是倒数第二个黑线,我们是要把下一个视为插入的元素,那么就是要他们在他们这些线的倒数第二个元素之前都可以,但是也同样不能碰到后面的那几个,因为他们彼此是最后一个元素,所以只有n-gap处于刚刚好的位置。
这是排的一组黑线,如果要全排完,看下面
完全版,希尔排序:一组一组的排版
void ShellSort(int*a,int n){ //按gap分组数据进行排,说白了就是预排处理 int gap=3; for(int j=0;j<gap;++j) for(int i=j;i<n-gap;i+=gap) int end=i; int x=gap+end; while(end>=0){ if(a[end]>x){ a[end+gap]=a[end]; end-=gap; } else { break; } a[end+gap]=x; } } }
多组一起排版:
void ShellSort(int*a,int n){ //按gap分组数据进行排,说白了就是预排处理 int gap=3; for(int i=0;i<n-gap;++i){ int end=i; int x=gap+end; while(end>=0){ if(a[end]>x){ a[end+gap]=a[end]; end-=gap; } else { break; } a[end+gap]=x; } } }
多组一起排:也就是将9和5先换,然后1和7.。,都给他排一遍
希尔排序,也就是预排序可以进行多次,
因此诞生了 多组预排序➕直接插入(gap==1)假如gap ==1希尔排序就会变成直接插入排序
void ShellSort(int*a,int n){ //按gap分组数据进行排,说白了就是预排处理 int gap=n; while(gap>1){ gap/=2 //或者gap=gap/3+1 for(int i=0;i<n-gap;++i){ int end=i; int x=gap+end; while(end>=0){ if(a[end]>x){ a[end+gap]=a[end]; end-=gap; } else { break; } a[end+gap]=x; } } }
gap无论是上面的除二还是除3最后都必须保证有一个个数是一个一,所以是看N来进行选择gap 到底要选择什么。
所以最好的是O(n)自然有顺序
最坏是换组拿最大的换也就是 (1+2+……+到N/gap)*gap 算是拿那个一组一组的gap分的
将gap带入N/2 最后时间复杂度差不多是N*logN
选择排序:
void Swap(int*ps,int*py){ int tmp=*ps; *ps=*py; *py=tmp } void SelectSort(int*a,int n){ int begin=0; int end=n-i; while(begin<end){ //奇数的话会自己相等,偶数的话会自己错开 int mini=begin; //随便给个值,但不可以不给,不能选值而是选择下标 int maxi=begin; if(a[i]<a[mini]){ mini=i; } if(a[i]>a[maxi]){ maxi=i; }//找最大和最小下标 Swap(&a[begin],&a[mini]); if(begin==maxi){ //这一步很重要,具体下面具体阐述 maxi=mini; } Swap(&a[end],&a[maxi]); ++begin; --end; } }
选择排序,先找最大和最小的,两个两个来,然后两个次大的和次小的。。。一直一直直到彼此错开。
如果没有注释的那行代码,会导致最大的和begin在一个位置,这样1和begin换位置的同时,最大的位置26改变,但是maxi的位置却没有改变,导致,maxi位置在交换的时候会出现错误。
选择排序的缺点就是时间复杂度O(N^2) 因为不管是顺序还是逆序我们都要进行遍历一遍,然后再判断谁是最大的,谁是最小的,所以复杂度会很高