我们知道,对于有序数据序列进行查找,二分查找法性能是相当好的,时间效率达到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;
}