我们如果仅仅是把书整理在书架上,要找到一本书还是比较困难的,也就是用8.2节的顺序查找表,但如果我们在整理书架时,将图书按书名的拼音排序放置,那么要找到一本书就相对容易了。简单的说,就是对图书做了有序排列,一个线性表有序时,对于查找总是很有帮助的。

8.3.1折半查找

折半查找:又叫二分查找(binary search)。它的前提是线性表中的记录必须是关键码有序(通常从小到大),线性表必须采用顺序存储。折半查找的基本思想:在有序表中,选中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;若给定值大于中间记录的关键字,则在中间记录的右半区继续查找。不断重复上述过程,直到查找成功,或所有的查找区域无记录,查找失败。

 

#include 
#include 
int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int BinarySearch(int *a, int n, int key)
{
int low;
int high;
int mid;
low = 0;
high = n - 1;
while(low<=high)
{
mid = (low + high)/2;
if(keya[mid])
low = mid + 1;
else
return mid;
}
return -1;
}
int main()
{
int addr;
int key = 2;
addr = BinarySearch(arr, 10, key);
if(addr == -1)
printf("查找失败\n");
else
{
printf("查找成功\n");
printf("所在位置为:%d\n",addr);
}
return 0;
}

8.3.2插值查找

我们现在的新问题是,为什么一定要折半,而不是四分之一或者折更多呢。

打个比方,在英文词典里查找“apple”,你会下意识的翻到靠前的书页,而不是从字典的中间开始查找。

插值查找:根据关键字key于查找表中最大最小记录的关键字比较后的查找方法。

在折半查找中 mid = (low + high)/2 = low + 1/2(high - low);

插值查找:mid= ((key - a[low])/(a[high] - a[low])) * (high - low); 

8.3.3斐波那契查找

利用黄金分割原理来实现。

斐波那契数列:0 1 1 2 3 5 8 13 21 34 ......

#include 
#include 
int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int F[10] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34};
int FibonacciSearch(int *a, int n, int key)
{
int low;
int high;
int mid;
int i;
int k;
low = 0;
k = 0;
high = n - 1;
while(n>F[k])
k++;
for(i=n; ia[mid])
{
low = mid + 1;
k = k - 2;
}
else
{
if(mid < n-1)
return mid;
else
return n-1;
}
}
return -1;
}
int main()
{
int addr;
int key = 2;
addr = FibonacciSearch(arr, 10, key);
if(addr == -1)
printf("查找失败\n");
else
{
printf("查找成功\n");
printf("所在位置为:%d\n",addr);
}
return 0;
}

3种算法的比较

折半查找:mid= (low + high)/2 = low + 1/2(high - low);//加法,乘法

插值查找:mid=low + ((key - a[low])/(a[high] -a[low])) * (high - low); // 乘法、除法。

斐波那契查找:mid = low + F[k] - 1;//加法

斐波那契算法效率高。