折半、二路插入排序
折半插入排序:直接插入排序是将待插入元素与前面的元素一一比较,寻找合适的位置插入。而折半插入是通过折半来查找位置,所谓折半(可以参考二分查找)就是定义两个变量分别指向头start和尾end,取其中间值mid。如果待插入元素大于mid位置上的元素就这mid和end之间再查找,如果小于,则在start和mid之间查找。然后不断缩小范围,直到寻找到合适的位置(大于左边小于右边),然后就是元素的插入。
1 #include<stdio.h> 2 #define n 6 3 4 5 void binaryInsertSort(int num[]){ 6 7 int start,end,mid,i,j,t; 8 for(i=1;i<n;i++){ 9 start = 0; //开始位置从0开始 10 end = i-1; //结束位置在待插入元素的前一个位置 11 while(start<=end){ //循环条件 12 mid = (start+end)/2; 13 if(num[i]>=num[mid]) //如果此条件成立 14 start = mid + 1; //就说明待插入元素的插入位置应该在mid和end之间 15 else 16 end = mid - 1; //否则说明待插入元素的插入位置应该在start和mid之间 17 } 18 19 if(start>mid) //如果start>mid,说明待插入元素比mid位置的元素大,但比mid+1位置上的元素小 20 mid++; //此时插入位置应该是mid+1 21 //还有一种情况就是end<mid,说明待插入元素比mid位置的元素小 22 //此时插入位置应该是mid 23 24 t = num[i]; //此处就是元素的插入 25 for(j=i-1;j>=mid;j--) //使用直接插入排序代码思想在此处插入元素 26 num[j+1] = num[j]; 27 num[j+1] = t; 28 29 } 30 31 }
二路插入排序:前面的插入排序每次插入元素的时候都会移动较多的元素,二路插入排序对其进行了改善。思路是:以第一个元素作为比较元素,后面所有大于该元素的数全部放在前面,所有小于元素的数放在后面,大于或小于部分的元素在插入的时候使用直接插入排序来保证有序,当所有元素分配好后,其实数组已经变成两个有序区,在组合好就完成排序了。
定义first、final指向两个有序区,图解如下:
1 #include<stdio.h> 2 #define n 6 3 4 5 void twoInsertSort(int num[]){ 6 7 int i,j,first,final,temp[n+1]={0}; //临时存放数组比原有数组多一个空间 8 first = 0; //first、final分别指向临时存放数组的开头和结尾 9 final = n; 10 temp[0] = num[0]; //数组第一个元素作为比较元素 11 12 for(i=1;i<n;i++){ 13 if(num[i]>=num[0]){ //大于第一个元素的数放在临时数组的前面 14 j = first; //first作为大于第一个元素的数的最后元素的下标 15 while(num[i]<=temp[j]){ //在这里使用直接插入,使其有序 16 temp[j+1] = temp[j]; 17 j--; 18 } 19 temp[j+1] = num[i]; 20 first++; 21 } 22 else{ 23 j = final; //小于第一个元素的数放在临时数组的后面 24 while(num[i]>temp[j]){ //在这里使用直接插入,使其有序 25 temp[j-1] = temp[j]; 26 if((++j)>=n+1) //这里是为了防止数组向后越界 27 break; 28 } 29 temp[j-1] = num[i]; 30 final--; //final作为小于第一个元素的数的最前元素的下标 31 } //但final指向了最前元素的前一个位置 32 } 33 34 for(i=0;i<n-1-first;i++) //将临时数组存放到原来的数组 35 num[i] = temp[++final]; 36 37 for(j=0;i<n;j++,i++) 38 num[i] = temp[j]; 39 40 } 41 42 void main(){ 43 44 int i,num[n] = {890,761,812,761,810,261}; 45 twoInsertSort(num); 46 47 for(i=0;i<n;i++) 48 printf("%d ",num[i]); 49 50 }