在二分查找中,我们是取mid等于left和right的中间值,即用等分的方法进行查找。
那为什么一定要等分呐?能不能进行“黄金分割”?也就是mid=left+0.618(right-left),当然mid要取整数。如果这样查找,时间复杂性是多少?也许你还可以编程做个试验,比较一下二分法和“黄金分割”法的执行效率。
(本例用C语言中的CLOCK来测定程序时间)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAXLength 10000000
struct Node {
int Element[MAXLength];
int Length;
};
typedef struct Node *List;
clock_t start1, stop1, start2, stop2;
double duration;
int BinarySearch (List Tbl, int K);
int GoldenSearch (List Tbl, int K);
int main(){
int i, j, result;
List Tbl = (List) malloc(sizeof(struct Node));
Tbl->Length = MAXLength-1;
for (i=0;i<MAXLength;i++){
Tbl->Element[i] = i;
}
start1 = clock();
for (j=1;j<=MAXLength-1;j++){
result = BinarySearch (Tbl, j);
}
stop1 = clock ();
duration = ((double)(stop1-start1))/CLK_TCK/(MAXLength-1);
printf ("Duration of BinarySearch is %6.2es.\n", duration);
start2 = clock();
for (j=1;j<=MAXLength-1;j++){
result = GoldenSearch (Tbl, j);
}
stop2 = clock ();
duration = ((double)(stop2-start2))/CLK_TCK/(MAXLength-1);
printf ("Duration of GoldenSearch is %6.2es.\n", duration);
return 0;
}
int GoldenSearch (List Tbl, int K){
int left, right, mid, NoFound = -1;
left = 1;
right = Tbl->Length;
while (left<=right){
mid=left+0.618*(right-left);
if(K<Tbl->Element[mid]) right = mid-1;
else if (K>Tbl->Element[mid]) left = mid+1;
else return mid;
}
return NoFound;
}
int BinarySearch (List Tbl, int K){
int left, right, mid, NoFound = -1;
left = 1;
right = Tbl->Length;
while (left<=right){
mid = (left+right)/2;
if(K<Tbl->Element[mid]) right = mid-1;
else if (K>Tbl->Element[mid]) left = mid+1;
else return mid;
}
return NoFound;
}
算了下在一个长度为MAXLength、a[i]等于i的数组里面,找一个i平均要花的时间。让MAXLength等于10000000。
输出:
Duration of BinarySearch is 1.35e-007s.
Duration of GoldenSearch is 2.74e-007s.
二分法每次能有100%的概率能只剩50%的数据,每次剩下的期望为50%,即每次除以2。所以时间复杂度是。
而黄金分割的话每次都有0.618的概率剩0.618,0.382的概率剩0.382,每次剩下的期望为0.528,即每次除以1.894。所以时间复杂度是。
虽然两者都是O(logN)类,但是系数不同,黄金分割法所需时间约为二分法的1.085倍(此处没考虑取整……)。
假设分割点距左侧的距离除以全长等于p,那么每次剩下的期望为个全长。要让这个期望最小,我们知道p要等于1-p。所以p=0.5。所以二分法分在正中。