1. 程式人生 > >【原創】啟發式查詢

【原創】啟發式查詢

啟發式查詢|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)