我們知道,對於有序資料序列進行尋找,二分尋找法效能是相當好的,時間效率達到O(Log2N),但該演算法其實還有些可以進行改進的地方。
普通的二分尋找法,直接通過折半的方式來對有序資料序列進行篩選,這種方法實際上不是十分有效。對於大多數的有序資料序列,通常分布都是比較均勻的,我們完全可以通過對資料的分布進行估算,找出合理位置,減少折半次數。
基於估算資料序列折點的方式進行尋找,在資料分布最好的情況下,與二分尋找法一樣,時間效率都是O(1), 但在最壞的情況下,與普通情況下,都有著比二分尋找法,更優越的情能。
以下是一個簡單的估算尋找法實現:
#include <cstdlib>
#include <iostream>
using namespace std;
//普通估演算法,沒有對分布不均勻的情況進行特殊處理
int fEval(int a[], int first, int last, int targe)
{
int nDevValue = 0;
nDevValue = (a[last] - a[first]) / (last - first);
if ((a[last] - a[first]) % (last - first) != 0)
++nDevValue;
int nDev = (targe - a[first]) / nDevValue;
if (targe - a[first] < nDevValue)
return first + nDev + 1;
else
return first + nDev;
}
//對分布不均勻的情況,進行了特殊(跳躍式)處理
int fEval2(int a[], int first, int last, int targe)
{
int cValue = a[(first + last)/2];
if (cValue > targe)
{
return fEval(a, first, (first + last)/2, targe);
}
else
{
return (first + last)/2 + fEval(a, (first + last)/2, last, targe);
}
}
//普通二分尋找法
int fBin(int a[], int first, int last, int targe)
{
return (first + last) / 2;
}
template<typename EVAL>
int Find(int a[], int first, int last, int targe, EVAL feval)
{
int result = -1;
int count = 0;
int nEvalFirst = first;
int nEvalLast = last;
int nEvalMid = 0;
while ((nEvalFirst < nEvalLast)
&& (a[nEvalFirst] <= targe)
&& (a[nEvalLast] >= targe))
{
nEvalMid = feval(a, nEvalFirst, nEvalLast, targe);
if (targe == a[nEvalMid])
{
result = nEvalMid;
break;
}
else if (nEvalMid != nEvalLast && targe > a[nEvalMid])
{
nEvalFirst = nEvalMid + 1;
}
else if (nEvalMid != nEvalLast && targe < a[nEvalMid])
{
nEvalLast = nEvalMid;
}
else
{
break;
}
++count;
}
cout << count << "/n";
return result;
};
int main(int argc, char *argv[])
{
//最差情況
int a[] = {1, 2, 3, 4, 5, 100, 400};
cout << Find(a, 0, 6, 201, fBin) << "/n";
cout << Find(a, 0, 6, 201, fEval) << "/n";
cout << Find(a, 0, 6, 201, fEval2) << "/n";
//最好情況
int b[] = {1, 2, 3, 4, 5, 6, 7};
cout << Find(b, 0, 6, 4, fBin) << "/n";
cout << Find(b, 0, 6, 4, fEval) << "/n";
//普通情況
int c[] = {1, 4, 6, 10, 15, 17, 20, 26, 40, 45, 48, 50, 52, 57, 59, 63,
68, 74, 78, 82, 85, 93, 96, 101, 105, 109, 112, 117, 120, 121,
123, 129, 133, 136, 140, 145, 147, 151, 154, 160, 163, 167,
170, 176, 179, 180, 183, 187, 188, 192, 194, 197, 201, 204,
210, 211, 215, 217, 220, 223, 225, 228, 231, 233, 237, 240,
245, 247, 248, 256, 258, 261, 263, 267, 269, 272, 275, 277,
279, 282, 283, 285, 289, 294, 297, 300};
cout << Find(c, 0, 85, 123, fBin) << "/n";
cout << Find(c, 0, 85, 123, fEval) << "/n";
system("PAUSE");
return EXIT_SUCCESS;
}