几种查找算法总结与比较—顺序查找、有序查找、散列表查找

  • Post author:
  • Post category:其他




静态查找表





只进行查找操作的查找表



动态查找表:


在查找过程中同时插入查找表中不存在的元素,或者删除已存在的元素

本文主要总结静态查找表



1.顺序表查找:


从第一个或者最后一个记录开始,将每个记录的关键字与给定值比较,若相等则查找成功。

C++实现:

for(int i=0;i<n;i++)

{

if(a[i]==key)

return i;

}

return 0;

时间复杂度:

最好情况:O(1),第一次就找到

最坏情况:O(n),需要逐个比较完

平均:O(n)



2.有序表查找:


元素是有序排列的,且是顺序存储的(存在数组或者vector)。主要包括二分查找,插值查找,斐波拉契查找



2.1二分查找(折半查找)

基本思想:

(1)与中间元素比较,其中mid=low+1/2*(low+high)

(2)等于中间元素,则查找成功

(3)大于中间元素,在它的右半区查找,重复(1);小于中间元素,在它的左半区查找,重复(1),直到找到给定值。

C++实现:

//n是有序表长度

int low=0,high=n-1;

while(low<high)

{

int mid=(low+high)/2;

if(key<a[mid])

high=mid-1;

else if(key>a[mid])

low=mid+1;

else

return mid;

}

return 0;

时间复杂度:

最好:O(1)

最坏:O(logn+1)

平均:O(logn)



2.2插值查找(折半查找升级版)

二分查找中:

mid=low+1/2*(low+high)

插值查找:



mid = low + (key – a[low]) / (a[high] – a[low]) * (high – low),也就是将上述的比例参数1/2改进了,根据关键字在整个有序表中所处的位置,让mid值的变化更靠近关键字key,这样也就间接地减少了比较次数


因为如果在一个有序表中找相对较小的元素(即离low更近一点),就mid向low靠近一点;找相对较大的元素(即离high更近一点),就mid向high靠近一点;这样效率比较高。但要求表中元素分布比较均匀。

时间复杂度:O(logn)



2.3斐波那契查找

斐波拉契数列:0,1,1,2,3,5,8,13,21,34,F(k)

基本思想:

(1)将有序数组的数值补全,使它的长度等于某个斐波拉契数F(k)-1

(2)取low=0,mid=low+F(k-1)-1,high=F(k)-2

(3)当给定值小于a[mid]值,在mid前半段查找,且前半段长度为F(k-1)-1;当给定值大于a[mid]值,在mid后半段查找,且后半段长度为F(k-2)-1;重复(2)

时间复杂度:O(logn)

因为斐波拉契查找求mid=low+F(k-1)-1,只有加减法,没有乘法,这种细微差别相比较前两种方法要好一些。

C++实现:

int low=0,high=n-1,mid,k=0;

while(n>F(k))

k++;

for(i=n;i<F(k)-2;i++)

a[i]=a[n-1];

while(low<high)

{

mid=low+F(k-1)-1;

if(key<a[mid])

{

high=mid-1;

k=k-1;

}

else if(key>a[mid])

{

high=mid+1;

k=k-2;

}

else

{

if(mid<=n) return mid;

else return n;  //是后面补的

}

return 0;



3.散列表查找(哈希表,hash table)

散列表:关键字key和存储位置之间有一个确定关系f,称为散列函数(哈希函数),要找到关键字key,只需计算f(key)就可以直接得到存储位置。连续存储。查找复杂度O(1)。

但有时候两个不同的关键字k1和k2,f(k1)=f(k2),会产生冲突。这就尴尬了……所以尽量构造散列函数让冲突尽可能少。



版权声明:本文为code_caq原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。