算法介绍:
斐波那契搜索就是在二分查找的基础上根据斐波那契数列进行分割的。在斐波那契数列找一个等于略大于查找表中元素个数的数F[n],将原查找表扩展为长度为Fn,完成后进行斐波那契分割,即F[n]个元素分割为前半部分F[n-1]个元素,后半部分F[n-2]个元素,找出要查找的元素在那一部分并递归,直到找到。
查找步骤:
同二分查找
注意事项:
为什么需要将临时数组的长度设置为F(k) - 1,看下图:
数组长度为F(k) - 1
;
左区间长度为F(k - 1) - 1
;
右区间长度为F(k - 2) - 1
;
middle节点只有一个,长度为1
因为公式成立:
F(k) - 1 = F(k - 1) + F(k - 2)
所以下面公式也成立:
F(k) - 1 = F(k - 1) - 1 + 1 + F(k - 2) - 1
即
F(k) - 1 = (F(k - 1) - 1)(左区间元素个数) + 1(middle元素个数) + (F(k - 2) - 1)(右区间元素个数)
实现代码:
// 获取fibonacci数列
void GetFibonacciArray(int* pData, int destIdx)
{
if (nullptr == pData || destIdx < 2) return;
pData[0] = 1;
pData[1] = 1;
for (int idx = 2; idx < destIdx; ++idx) pData[idx] = pData[idx - 1] + pData[idx - 2];
}
int FibonacciSearch(int* pData, int size, int value)
{
if (nullptr == pData || size < 1) return -1;
// 构造fibonacci数组
const int FIBONACCI_MAX_IDX = 20;
int* pFibData = new int[FIBONACCI_MAX_IDX];
GetFibonacciArray(pFibData, FIBONACCI_MAX_IDX);
// 获取第一个大于等于size + 1的fibonacci数, 或许写成pFibData[destIdx] < size + 1更加清晰些
int destIdx = 0;
while (pFibData[destIdx] - 1 < size) ++destIdx;
// 构造临时数组,元素个数为pFibData[destIdx] - 1, 为了使用fibonacci算法,将临时数组长度扩充至pFibData[destIdx] - 1
int* pTempData = new int[pFibData[destIdx] - 1];
// 将pData中的数据复制到pTempData(原本空间)
memcpy(pTempData, pData, size * sizeof(int));
// pTempData剩余的空间(扩充空间)用pData中最后一个值进行赋值
for (int idx = size; idx < pFibData[destIdx] - 1; ++idx) pTempData[idx] = pData[size - 1];
int left = 0;
int right = size - 1;
while (left <= right)
{
int middle = left + pFibData[destIdx - 1] - 1;
if (value == pTempData[middle]) // 找到
{
if (middle < size) return middle; // 元素位于原本空间中,直接返回下标
else return size - 1; // 元素位于扩充空间,因为扩充空间都是用pData[size - 1]进行的赋值,所以返回下标size - 1
}
else if (value > pTempData[middle]) // 右区间查找
{
left = middle + 1;
destIdx = destIdx - 2;
}
else // 左区间查找
{
right = middle - 1;
destIdx = destIdx - 1;
}
}
delete [] pTempData;
delete [] pFibData;
return -1;
}