1.4.22 #
解答 #
普通二分查找是通过除法不断减半缩小搜索范围。
这里我们用斐波那契数列来缩小范围。
举个例子,例如数组大小是 100,比它大的最小斐波那契数是 144。
斐波那契数列如下:0 1 1 2 3 5 8 13 21 34 55 89 144
我们记 F(n) = 144,F(n-1) = 89, F(n-2) = 55。
我们先查看第 0 + F(n-2) 个数,如果比关键值小则直接将范围缩小到 [55, 100];否则则在[0, 55]之间查找。
之后我们令 n = n-1。
递归上述过程即可完成查找。
代码 #
/// <summary>
/// 使用斐波那契数列进行的查找。
/// </summary>
/// <param name="a">查找范围。</param>
/// <param name="key">关键字。</param>
/// <returns>返回查找到的关键值下标,没有结果则返回 -1。</returns>
static int Rank(int[] a, int key)
{
// 使用斐波那契数列作为缩减范围的依据
var fk = 1;
var fk1 = 1;
var fk2 = 0;
// 获得 Fk,Fk需要大于等于数组的大小,复杂度 lgN
while (fk < a.Length)
{
fk = fk + fk1;
fk1 = fk1 + fk2;
fk2 = fk - fk1;
}
var lo = 0;
// 按照斐波那契数列缩减查找范围,复杂度 lgN
while (fk2 >= 0)
{
var i = lo + fk2 > a.Length - 1 ? a.Length - 1 : lo + fk2;
if (a[i] < key)
{
lo = lo + fk2;
}
else if (a[i] == key)
{
return i;
}
fk = fk1;
fk1 = fk2;
fk2 = fk - fk1;
}
return -1;
}