最近在PTA上遇到排序题,题目为:
刚开始想用冒泡法进行排序,发现冒泡法排序测试时间为10s,超出题目所限时长,冒泡法的时间复杂度为O(n^2),为了进一步降低题目的时间复杂度,突发奇想,借鉴二分查找的思想,建立了二分插入法,其时间复杂度为O(nlogn)。
其基本思路为:首先建立一个题目所要求大小的数组,每当输入一个,新的数据,采用二分法的思路查找新数据在递增数组中的位置,然后插入数组。实现的具体步骤为:
对于第i个数据number(对应数组大小为i+1),应插入序号为p
-
lower=0;upper=max(i-1,0);
-
若number<=a[0];p=0;//新数据在0位
-
若number>=a[upper],p=i;//新数据在第i位
-
若upper-lower=1,结束循环,p=upper;//新数据在lower和upper之间
-
若numer=a[(upper+lower)/2),p=(upper+lower),跳出循环; //新数据在(upper+lower)/2
-
若number>a[(upper+lower)/2],lower=(upper+lower)/2;
-
若number<a[(upper+lower)/2],upper=(upper+lower)/2;
-
返回第4步;
二分插入与二分查找最大的区别在于新数据可能在原数组中没有重复的数据,新数据位于两个数据元素之间,首先判断新数据是否大于或等于原数组的最大值或者最小值,排除了lower和upper在数组两端的可能性,之后upper和lower都由(upper+lower)/2赋值过来,因此不可能等于upper和lower对应的数组元素,当upper和lower差值位1时,新数组必然在a[lower]和a[upper]之间,应插入位置为p=upper。
代码如下:
#include <stdio.h>
#include <stdlib.h>
int main(){
int n=6;
//int b[]={5,4,3,2,1,3};
scanf("%d",&n);
int* a=(int*)malloc(n*sizeof(int));
int i=0;
int number;
a[0]=0;
int upper=0;
int lower=0;
int p=0;
for(i=0;i<n;i++){
scanf("%d",&number);
// number=b[i];
// number=rand();
lower=0;
upper=((i-1)<0)?0:(i-1);
int isFound=0;
if(number<=a[0]) {
p=0;
isFound=1;
}
else if(number>=a[((i-1)<0)?0:(i-1)]){
p=i;
isFound=1;
}
else{
while(upper>lower+1){
if(number==a[(upper+lower)/2]){
p=(upper+lower)/2;
isFound=1;
break;
}
else if(number>a[(upper+lower)/2]){
lower=(upper+lower)/2;
}
else {
upper=(upper+lower)/2;
}
}
}
if(isFound==0) p=upper;
int j=0;
for(j=i;j>p;j--){
a[j]=a[j-1];
}
a[p]=number;
/*if(a[p]<a[p-1<0?0:p-1]){
printf("在a[%d]=%d和a[%d]=%d中插入%d,此时i=%d,upper=%d,lower=%d,isFound=%d\n,",p-1<0?0:p-1,a[p-1<0?0:p-1],p+1>i?i:p+1,a[p+1>i?i:p+1],a[p],i,upper,lower,isFound);
int j=0;
for(j=lower;j<=upper+1;j++) printf("a[%d]=%d ",j,a[j]);
printf("\n\n");
}*/
}
//nt error=0;
for(i=0;i<n-1;i++){
// if(a[i]>a[i+1]) {
// error=1;
// printf("%d > %d\t",a[i],a[i+1]);}
printf("%d ",a[i]);
}
printf("%d",a[i]);
free(a);
return 0;
}
最后总结一下二分缩近的规律:
- 2->{1,3}------->{1,2,3},p=upper;
- 2->{1,3,4}------>2->{1,3}(第一步)
- 2->{0,1,3,4}------->2->{1,3,4}(第二步)
因此当新数据在原数组中没有相等的数据是,upper和lower最终会等于1,如果有相等数据,则会率先满足number=a[(upper+lower)/2],跳出循环。