数据结构-查找

目录

顺序查找

带监视哨的顺序查找:

折半查找

折半查找算法实现

插值查找


查找是所有数据处理中最基本、最常用的操作。

查找:在数据集合中寻找满足某种条件的数据元素的过程称为查找

查找表: 相同类型的数据元素(对象)组成的集合,每个元素通常由若干数据项构成。
关键字(Key): 数据元素中某个(或几个)数据项的值,它可以标识一个数据元素。若关键字能唯一标识一个数据元素,则关键字称为主关键字;将能标识若干个数据元素的关键字称为次关键字。
查找/检索: 根据给定的K值,在查找表中确定一个关键字等于给定值的记录或数据元素。

平均查找长度:在查找的过程中,一次查找的长度是指需要比较的关键字的次数。平均查找长度则是所有查找过程中进行关键字的比较的次数的平均值。

 

如何判断查找算法的优劣性:查找运算时间主要花费在关键字比较上,通常把查找过程中执行的关键字平均比较个数(也称为平均查找长度)作为衡量一个查找算法效率优劣的标准。

顺序查找

它的查找过程是:从第一个(或者最后一个)记录开始,逐个进行记录的关键字和给定值进行比较,若某个记录的关键字和给定值相等,则查找成功。如果查找了所有的记录仍然找不到与给定值相等的关键字,则查找不成功。

下面是顺序表

int Search_Seq(SSTable ST, int key){
    //在顺序表ST中顺序查找其关键字等于key的数据元素。若找到,则函数值为
    //该元素在表中的位置,否则为0
     for (int i=ST.length; i>=1; --i)  
             if (ST.R[i].key==key) return i;		//从后往前找        
     return 0;
   }// Search_Seq

顺序查找时间复杂度:O(n)

带监视哨的顺序查找:

具体实现就是将数组的第0位置空,在查找时将要查找的key插入作为监视哨。

这样的好处是不用每次循环都检查查找是否结束,减少了元素比较次数,最后的返回值要么是元素下标要么是数组第0位(这种情况就是到了监视哨)。

int Search_Seq(SSTable ST, int key){
      //在顺序表ST中顺序查找其关键字等于key的数据元素。若找到,则函数值为
      //该元素在表中的位置,否则为0
     ST.R[0].key = key;                          			//“哨兵”
     for(int i = ST.length; ST.R[i].key!=key; --i)  ;		//从后往前找
     return i;                                         
}// Search_Seq

折半查找

折半查找又称为二分查找,折半查找的作用对象是有序的查找表,也就是说,我们的查找表是已经排好序的。之所以称为折半查找,是因为在每次关键字比较时,如果不匹配,则根据匹配结果将查找表一份为二,排除没有关键子的那一半,然后在含有关键字的那一半中继续折半查找。

对于这样一个顺序表,如果我们要查找G这个元素。下面是查找步骤:

(1)标记查找表的范围,查找表的初识范围就是整张表,所以查找表的下边界low=1,查找表的上边界high=8。查找表的中间位置mid=low+(high-low)/2=(high+low)/2 = 4。所以我们将G与mid所对应的D比较大小。比较结果为G>D。

(2)由上一步的比较结果,我们得知上面一轮中,前一半的数据是没有我们要查找的关键字G的。所以将前一半查找表中的数据进行丢弃,重新定义查找表的范围,因为mid处的元素以及匹配完毕了,要想丢弃前半部分的的数据,我们只需更新查找表的下边界移动到mid后方即可。也就是将查找表的范围缩小到上一步查找表范围的后半部分。此刻查找表的下边界low=mid + 1 = 4+1 = 5。查找表的下边界更新后,mid的位置也会变化,所以我们要对mid进行更新,mid的位置仍然是low和high的中心,mid = (high + low)/2 = (8+5)/2=6。此刻mid处的元素为F, 将G与F比较,可知G > F。


(3)由G>F这个结果,我们得出,上一轮查找表的前半部分的数据需要丢弃,所以要还需要更新low的值,low= mid + 1 = 6+1 = 7。 mid = (8+7)/2=7。此刻的mid处的元素是G, 所以找到的我们要找的值,返回mid = 7。

折半查找算法实现

int Search_Bin(SSTable ST,int key) {
   // 在有序表ST中折半查找其关键字等于key的数据元素。若找到,则函数值为
   // 该元素在表中的位置,否则为0
   int low=1,high=ST.length;							//置查找区间初值
   int  mid;
   while(low<=high) {
	   mid=(low+high) / 2;
      if (key==ST.R[mid].key)  return mid;      		//找到待查元素
      else if (key<ST.R[mid].key)  high = mid -1;		//继续在前一子表进行查找
      else  low =mid +1;                       			//继续在后一子表进行查找
   }//while
   return 0;										//表中不存在待查元素
}// Search_Bin

特别需要注意:折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。

折半查找时间复杂度是O(logn),不过由于折半查找的前提是需要有序表顺序存储,对于静态查找表,一次排序后不再变化,这样的算法是比较好的。但是对于需要频繁插入或删除操作的数据集来说,保持有序的排序会带来不小的工作量,不建议使用。

插值查找

很明显,折半查找只能是折半,而不是折四分之一等等。总的来说,折半查找这种查找方式,不是自适应的。

二分查找的计算方法:mid=(low+high)/2, 即mid=low+1/2*(high-low)

插值查找的计算方法:mid=low+(key-a[low])/(a[high]-a[low])*(high-low)

也就是将二分查找的比例参数1/2改进为自适应的值。对于表长较大,而关键字分布又比较均匀的查找表来说,插值查找算法的平均性能比折半查找要好的多。

插值查找算法实现

int InsertionSearch(int a[], int value, int low, int high)
{
    int mid = low+(value-a[low])/(a[high]-a[low])*(high-low);
    if(a[mid]==value)
        return mid;
    if(a[mid]>value)
        return InsertionSearch(a, value, low, mid-1);
    if(a[mid]<value)
        return InsertionSearch(a, value, mid+1, high);
}

插值查找的时间复杂度是O(log2n)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值