查找算法中的“二分法”是这样定义的:
给定N个从小到大排好序的整数序列List[],以及某待查找整数X,我们的目标是找到X在List中的下标。即若有List[i]=X,则返回i;否则返回-1表示没有找到。
二分法是先找到序列的中点List[M],与X进行比较,若相等则返回中点下标;否则,若List[M]>X,则在左边的子系列中查找X;若List[M]<X,则在右边的子系列中查找X。
试写出算法的伪码描述,并分析最坏、最好情况下的时间、空间复杂度。
#include "stdio.h"
int search_SS(int list[],int i,int length)
{
int result;
int low,mid,high;
low = 1;
high = length;
while(low <= high)
{
mid = (int)((low+high)/2.0);
if(list[mid] < i)
low = mid+1;
else if(list[mid] > i)
high = mid-1;
else
{
result = mid;
return result;
}
}
return result = -1;
}
int main()
{
int list[] = {1,2,3,4,5,6,7,8,9};
int i,length;
int result;
length = sizeof(list)/sizeof(int);
/*
向子函数传递数组后,然后在子函数内部获取数组长度。先来看一个错误示例程序:
[cpp] view plain copy
int getLength(int array[])
{
int length;
length=sizeof(array)/sizeof(array[0]);
return length;
}
len = getLength(array);
printf("The length of array is %d\n",len);
这样得到的结果始终都是1。因为数组作为参数传给函数时传的是指针而不是数组,
传递的是数组的首地址。在本示例中,函数名array传递到子函数后就完全退化为一个指针,
该指针指向的是数组array所在的地址,即数组array第一个元素array[0]所在的地址。
也就是说系统只是告诉该函数这个存储空间存有数据,但并没有告诉函数这个数据存储空间有多大。
sizeof(array)的结果是指针变量array所占内存的字节数,具体大小与系统有关,
一般在32位机器上占4个字节,array[0]是int类型,同样占4个字节,所以结果为1。
所以要获得数组的长度最好在数组定义所在的区域内。
*/
printf("数组长度为:%d\n",length);
printf("Please insert the number you want to search:\n");
scanf("%d",&i);
result = search_SS(list,i,length);
if(result == -1)
printf("Can not found %d in the list!\n",i);
else
printf("The number you found is in the %d position of list!\n",result);
}
时间复杂度最小为O(1),第一个就找到要找的数;
时间复杂度最大为O(log2 n),最后一次找到要找的数;
对于n个元素的情况:
第一次二分:n/2
第二次二分:n/2^2= n/4
......
m次二分:n/(2^m)
在最坏情况下是在排除到只剩下最后一个值之后得到结果,所以为
n/(2^m)=1;
2^m=n;
所以时间复杂度为:log2n 也即log(n);
第一次二分:n/2
第二次二分:n/2^2= n/4
......
m次二分:n/(2^m)
在最坏情况下是在排除到只剩下最后一个值之后得到结果,所以为
n/(2^m)=1;
2^m=n;
所以时间复杂度为:log2n 也即log(n);
空间复杂度两种情况下均为O(1);