【原创】启发式查询

来源:互联网 发布:汽车行业设计软件 编辑:程序博客网 时间:2024/05/16 16:03

启发式查询|Cacl_Search

此算法为bzy原创,转载务必获得允许(QQ:1143710044)

从一个单调队列中查询一个数字的位置一直是一个困扰人们的问题。
这个问题一直有一个十分简易的方法叫做搜索
实现如下:

int normal_Search(int *line,int value,int ub){    for(int i = 0;i <= ub ;i ++){        if(line[i] == value)return i;     }    return 0;}


O(n)的算法很显然有些慢,在运算100’000数据量1000’000次直接bz(1000s),显然不能满足
人们日益增长的追求美好生活的追求,于是聪明的先祖想出了二分查找

二分查找|Bianry_Search



学过OI/ACM肯定学过这个算法,它在计算机领域广泛运用,所以关于它的描述就从略。
二分查找是一种将单调队列从中间分快的方法,是已知运用最广泛的算法之一,代码如下:

int Binary_search(int *line,int value,int ub){    int down = 0,up = ub;    while(1){        int mid = (up + down)>>1;        if (line[mid] == value)return mid;        if (line[mid] >  value){            up = mid - 1;        }else {            down = mid + 1;        }    }    return 0;}


看完代码,其精髓思想便一目了然,O(log2n)的时间复杂度和极地的常数使得它速度极快,同普通搜索一样的数据量它用时仅为1.6 - 2.0秒.
但是本着精益求精的思想,bzy想出了一个算法可以在常数上胜过二分查找,这就是启发式查询

!!!重头戏登场

启发式查询|Cacl_Search


已知单调队列 {Linei},其长度为ubount其对首记做Line[ 1 ],其尾记做Line[ ub ],所搜索的值记做Value,由此,我们可以近似估计Line 是一个等差数列,即可估计Value的位置大概在:
estimate = 1+(ub-1) *(value-line[1]) / (line[ub]-line[1]);
当然这个式子估计的位置只是估计值,不一定正确,当我,们可以确定范围,用Line[ estimate ]与value比较,如果大则范围在1 - estimate之间,否则在estimate-ub之间,直到有一个正确的estimate出现则返回即可,
代码如下:

inline const int Cacl_Search(int *line,const int value,const int ub){    int down = 0;register int up=ub;    while(1){        register int estimate = down +         (long long)(up - down) *        (long long)(value -line[down]) /         (line[up] - line[down]);        if(estimate == down) ++ estimate ;        if(estimate == up  ) -- estimate ;        if(line[estimate] == value)return estimate;        (line[estimate] < value?down:up) = estimate;    }    return 0;}


在常数优化下运行同样数据只需1.1 - 1.2s,显然比二分查找快了很多.
这个算法时间复杂度不好估计,但效率较高,在卡常数时有一定作用.

后记|RP_search


最后送给大家一个测试人品的算法:

    int down = 0,up = ub;    srand(233);'种子随意,看人品    while(1){        if(up == down)return down;        register int estimate = down +         (long long)(up - down) *        (long long)(value -line[down]) /         (line[up] - line[down]);        if(line[estimate] == value)return estimate;        int mid = down + rand()*rand()%(up - down);        if (line[mid] == value)return mid;        if(line[mid]>value){            up = mid - 1;        }else {            down = mid + 1;        }    }    return 0;

此算法为bzy原创,转载务必获得允许(QQ:1143710044)