查找(1)

查找在生活中无处不在,电话簿找朋友电话,好友列表找人,聊天记录找历史记录等都用到查找。

比如拿到一个杂乱无章的文章,我们会挨个比对,依次去找某个字,这叫顺序查找;

拿起一本700多页的书,我们想翻到第340页,通常会目测,然后把书从中间翻开,如果翻到380页,就再往前面拿起一部分对半,知道找到;如果翻到320页,则往后面拿起一部分对半分,直到找到。这叫折半查找

当你拿起一份长长的职工信息表,你想找名字叫“李四”的信息,你会想到按职工号来找把,这体现了索引结构实现查找;

当你想从电话簿中找出姓郭的人,你通常不会从第一个找起,也不会从最中间开始,也不会从最后边开始,你会习惯性的从电话簿前面些的地方开始找,这体现了插值查找;

当你面前有100个人(假设没重名的),你想快速找出名字为“小明”的人,你会怎么做呢?折半,顺序,插值查找?这些显然太low了,你会直接喊某某出来就可以了。这体现了散列表查找的思想。

————————————————————————————————————————————————————————

一、基本概念

(1)查找

人话:按某个标准去查找想要的东西

术语:在数据集合中找出满足某种条件的数据元素

       (查找环境分为:态查找结构和态查找结构)

(2)查找表

         用于查找的数据集合称为查找表,它由同一类数据的数据元素组成。

         对应的查找表分为:

         静态查找表:不涉及动态修改查找表  ,比如:顺序查找,折半查找,散列查找

         态查找表:需要动态插入或删除查找招表,比如:二叉排序树的查找,散列查找等

(3)平均查找长度

           在查找过程中,一次查找的长度是指需要比较的关键字次数,而平均查找长度则是所有查找过程中进行关键字比较次数的平均值ASL=\sum_{n}^{i=1}P_{i}C_{i}

         n为查找表的长度;Pi是查找第i个数据元素的概率,通常认为概率相等为1/n;Ci是查找到第i个数据元素所需要的表较次数。

平均查找长度是衡量查找算法效率的最主要的指标。

二、顺序查找

定义:从线性表的一端开始,逐个检查关键字是否满足给定条件,若满足则查找成功,返回该元素在线性表中的位置。

若已经查找到表的另一端(一般为末端),仍没有查找到符合条件的元素,则返回查找失败的信息。

个人理解的顺序查找,下面进行的是数组上的查找

#include<stdio.h>
#include<stdlib.h>
void Search(int arr[],int n,int key)
{
	int i=0;
	while(i<n&&arr[i]!=key)
		{
		  i++; 	
		}
		if(i>=n)printf("no\n");
		else printf("%d\n",i);
}
int main(){
		int k1=5,k2=100,i=0;
		int arr[]={3,4,5,6,1,2,32,2};
		int n=sizeof(arr)/sizeof(int);
		Search(arr,n,k1);
		Search(arr,n,k2);
		return 0;
} 

(1)在普通顺序表上的顺序查找

//顺序表上的顺序查找算法
int SeqSearch(SeqList & L,DataType x){
    int i=0;
    while(i<L.n&&L.data[i].key!=x.key)  i++;
    return i;
}//

 

//使用了“监视哨”的顺序查找
int Search(SeqList & L,DataType x){
    L.data[L.n]=x;//将x设为监视哨
    int i=0;
    While(L.data[i].key!=x.key);//从前往后顺序查找
    return i;
};

 监视哨:

若找到则函数返回元素在该表中的位置,否则返回n。与无监视哨的算法相比,每次少了控制循环结束的条件判断语句i<L.n。

typedef struct{
    Elemtype *elem;   //元素空间基址,建表时按实际长度分配,0号单元留空
    int TableLen;  //表的长度
}SStable;
int Search_Seq(SSTable ST,Elemtype key){
    //在顺序表中关键字为key的元素,若找到则返回该元素在表中的位置
    ST.elem[0]=key; //哨兵
    for(i=ST.TableLen;ST.elem[i]!=key;--i);  //从后往前找
    return i;//若表中不存在关键字为key的元素,将i为0时退出for循环
 
}

上面这个从后往前找,把第一个设为哨兵,思想就是将key值赋给表中第一个元素,当当前值不等于于key,就一直往前找,当当前值等于哨兵(也就是key),返回i

(2)顺序查找的递归

int SeqSearch(SeqList &L,DataType x,int lic)
{   if(loc>=L.n) return -1;  //查找失败
    else if(L.data[loc].key==x.key)   //查找成功
         return loc;
         else return SeqSearch(L,x,loc+1); //递归查找后续部分
}

(3)在有序顺序表上的顺序查找

int  SqeSearch(SeqList & L,DataType x){
    for(int i=0;i<L.n;i++)
        if(L.data[i].key==x.key) return i;
        else if(L.data[i].key>x.key)  break;
    return -1;
}

查找成功的平均长度在等概率下为 n+1/2

查找不成功的平均长度在等概率下为 n/2+n/(n+1)

三、折半查找

基本思想为:

(1)若data[mid]=x,查找成功则报告成功并返回下标

(2)若x>data[mid],把查找区间缩小到表的前半部分,再继续进行折半查找

(3)若x<data[mid],把查找区间缩小到表的后半部分,再继续进行折半查找

非递归折半查找
int BinarySearch(SeqList &L,DataType x){
    int high=L.n-1,low=0,mid;
    while(low<high){
        mid=(low+high)/2;
        if(x.key>L.data[mid].key) low=mid+1;
        else if(x.key<L.data[mid].key) high=mid-1;
            else return mid+1;
}
return -1;
}
//递归折半查找
int BinarySearch(SeqList & L,DtaType x,int low,int high){
    int mid=-1;
    if(low<=high){
        mid=(low+high)/2;   //求中点
        if(x.key>L.data[mid].key)    //大于中点值,右缩查找区间
            mid=BinarySearch(L,x,mid+1,high);
        else if(x<L.data[mid].key) //小于中点值,左缩查找区间
            mid=BinarySearch(L,x,low,mid-1);
}//等于中点值,继续向下执行
return mid;    //返回中点位置或-1
}

对n个关键码有序顺序表,最多比较\left \lceil log_{2}{}(n+1) \right \rceil 次 ,平均查找长度log_{2}(n)

折半查找仅使用有序顺序表

#include<stdio.h>
#include<stdlib.h>
int binsearch(int arr[],int n,int key){
	int low=0;
	int high=n-1;
    while(low<=high){
        int mid=low+((high-low)>>1);
        if(arr[mid]==key) {
		return mid;
		continue; 
		}
        else if(arr[mid]<key) {
			low=mid+1;
		}else{
			high=mid-1;
		}
}
return -1;
}
int main(){
		int k1=8;
		int arr[]={3,4,5,6,1,2,32,2};		
		int n=sizeof(arr)/sizeof(int);
		printf("%d",binsearch(arr,n,k1));
		
		return 0;
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值