【原創】啟發式查詢
啟發式查詢|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;
}
看完程式碼,其精髓思想便一目瞭然,
但是本著精益求精的思想,bzy想出了一個演算法可以在常數上勝過二分查詢,這就是啟發式查詢。
!!!重頭戲登場
啟發式查詢| Cacl_Search
已知單調佇列 {
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)