总结:
博客详细描述:(http://www.cnblogs.com/maybe2030/p/4715035.html#_label4)
关注:
- 二分查找、插值查找以及斐波那契查找都可以归为一类插值查找;
- 插值查找和斐波那契查找是在二分查找的基础上的优化;
- 但由于数组中数据分布非常不均匀,所以插值查找效率未必好;
- 二分查找在静态查找表,一次排序后不再变化,得到不错的效率。但对于需要频繁执行插入或删除操作的数据集来说,维护有序的排序会带来不小的工作量,那就不建议使用。——《大话数据结构》
时间复杂度:
顺序查找:O(n)
二分查找:O(log2(n+1)) – O(log2n)
插值查找:O(log2(log2n))
斐波那契查找:O(log2n)
查找定义:
根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录)。
查找算法分类:
- 静态查找和动态查找;
注:静态或者动态都是针对查找表而言的。动态表指查找表中有删除和插入操作的表。 - 无序查找和有序查找。
无序查找:被查找数列有序无序均可;
有序查找:被查找数列必须为有序数列。
顺序查找
- 说明:
顺序查找适合于存储结构为顺序存储或链接存储的线性表。 - 时间复杂度分析:
查找成功时的平均查找长度为:ASL = 1/n(1+2+3+…+n) = (n+1)/2 ;时间复杂度为O(n)。
//顺序查找
int SequenceSearch(int a[], int value, int n)
{
int i;
for(i=0; i<n; i++)
if(a[i]==value)
return i;
return -1;
}
二分查找(折半查找)
- 说明:
也称为折半查找,属于有序查找算法。 - 时间复杂度分析:
最坏情况下,关键词比较次数为log2(n+1),且期望(最好)时间复杂度为O(log2n); - 优缺点:
折半查找的前提条件是需要有序表顺序存储,静态查找表,一次排序后不再变化,折半查找能得到不错的效率。但对于需要频繁执行插入或删除操作的数据集来说,维护有序的排序会带来不小的工作量,那就不建议使用。——《大话数据结构》
//二分查找(折半查找),版本1
int BinarySearch1(int a[], int value, int n)
{
int low, high, mid;
low = 0;
high = n-1;
while(low<=high)
{
mid = (low+high)/2;
if(a[mid]==value)
return mid;
if(a[mid]>value)
high = mid-1;
if(a[mid]<value)
low = mid+1;
}
return -1;
}
//二分查找,递归版本
int BinarySearch2(int a[], int value, int low, int high)
{
int mid = low+(high-low)/2;
if(a[mid]==value)
return mid;
if(a[mid]>value)
return BinarySearch2(a, value, low, mid-1);
if(a[mid]<value)
return BinarySearch2(a, value, mid+1, high);
}
插值查找
说明:
比如要在取值范围1 ~ 10000 之间 100 个元素从小到大均匀分布的数组中查找5, 我们自然会考虑从数组下标较小的开始查找。
折半查找:mid=low+1/2*(high-low);
插值查找:mid=low+(key-a[low])/(a[high]-a[low])*(high-low);时间复杂度分析:
查找成功或者失败的时间复杂度均为O(log2(log2n))- 优缺点:
对于表长较大,而关键字分布又比较均匀的查找表来说,插值查找算法的平均性能比折半查找要好的多。反之,数组中如果分布非常不均匀,那么插值查找未必是很合适的选择。
int insertSearch(int *sortedSeq, int seqLength , int keyData)
{
int low = 0, mid, high = seqLength - 1;
while (low <= high)
{
mid = low + (keyData - sortedSeq[low]) / (sortedSeq[high] - sortedSeq[low]);
if (keyData < sortedSeq[mid])
{
high = mid - 1;//是mid-1,因为mid已经比较过了
}
else if (keyData > sortedSeq[mid])
{
low = mid + 1;
}
else
{
return mid;
}
}
return -1;
}
斐波那契查找
说明:
二分查找的一种提升算法,通过运用黄金比例的概念在数列中选择查找点进行查找。
什么是黄金分割?
黄金比例又称黄金分割,是指事物各部分间一定的数学比例关系,即将整体一分为二,较大部分与较小部分之比等于整体与较大部分之比,其比值约为1:0.618或1.618:1。
0.618被公认为最具有审美意义的比例数字,这个数值的作用不仅仅体现在诸如绘画、雕塑、音乐、建筑等艺术领域,而且在管理、工程设计等方面也有着不可忽视的作用。
斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89…….时间复杂度分析:
最坏情况下,时间复杂度为O(log2n),且其期望复杂度也为O(log2n)。
/*构造一个斐波那契数组*/
void Fibonacci(int * F, int max_size)
{
F[0]=0;
F[1]=1;
for(int i=2;i<max_size;++i)
F[i]=F[i-1]+F[i-2];
}
/*定义斐波那契查找法*/
int FibonacciSearch(int *a, int n, int key, int * F) //a为要查找的数组,n为要查找的数组长度,key为要查找的关键字
{
int low=0;
int high=n-1;
int k=0;
while(n>F[k]-1)//计算n位于斐波那契数列的位置
++k;
while(low<=high)
{
int mid=low+F[k-1]-1;
if(key<a[mid])
{
high=mid-1;
k-=1;
}
else if(key>a[mid])
{
low=mid+1;
k-=2;
}
else
{
if(mid<n)
return mid; //若相等则说明mid即为查找到的位置
else
return n-1; //若mid>=n则说明是扩展的数值,返回n-1
}
}
return -1;
}