数据结构查找

目录

查找的基本概念

查找的运算

线性表的查找

顺序查找

折半查找

哈希表的查找

散列函数的构造方法

 处理冲突的方法

开放地址法


查找的基本概念

(1)查找表:是由同一类型的数据元素(或记录)构成的集合。由于”集合“中的数据元素之间存在着完全松散的关系,因此查找表是一种非常灵便的数据结构。

(2)关键字:是数据元素(或记录)中某个数据项的值,用它可以标识一个数据元素(或记录)。若此关键字可以唯一地标识一个记录,则称此关键字为主关键字(对不同的记录,其主关键字均不同)。反之,称用以识别若干记录的关键字为次关键字。当数据元素只有一个数据项时,其关键字即该数据元素的值。

(3)查找:是指根据给定的某个值,在查找表中确定一个其关键字等于给定值的记录或数据元素,。若表中存在这样一个记录,则称查找成功,此时查找的结果可给出整个记录的信息,或指示该记录在查找表中的位置;若表中不存在关键字等于定值的记录,则称查找不成功,此时返回一个”空“记录或”空“指针。

(4)动态查找表和静态查找表:若在查找的同时对表执行修改操作(如插入删除),则称相应的表为动态查找表,否则称之为静态查找表。

(5)平均查找长度:为确定记录在查找表中的位置,需和给定值进行比较的关键字个数的期望值,称为查找算法在查找成功时的平均查找长度.

 其中,n表示记录的个数 ,pi表示查找第i个记录的概率 ( 通常认为pi =1/n ), ci表示找到第i个记录所需的比较次数。

查找的运算

线性表的查找

顺序查找

适用范围:顺序表或线性链表表示的静态查找表,表内元素之间无序。

数据元素类型的定义

typedef struct
{
    KeyType key;          //关键字域
    InfoType otherinfo;   //其他域
}ElemType;

顺序表的定义

typedef struct  //顺序表结构类型的定义
{
    ElemType *R;    //顺序表的基地址
    int length;     //顺序表的表长
}SSTable; 
SSTable ST;   //定义顺序表ST

查找的算法

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

但是,该算法在查找过程中每一步都要检测整个表是否查找完毕,每一步都要有循环变量是否满足条件i>=1的检测。改进这个程序,可以免去这个检测的过程。

设置监视哨的顺序查找

把待查关键字key存入表头(“哨兵”),从后向前逐个比较,可免去查找过程中每一步都要检测是否查找完毕,加快速度。

int Search_Seq( SSTable  ST , KeyType  key )
{
   //若成功返回其位置信息,否则返回0
  ST.R[0].key =key;   
  for( i=ST.length; ST.R[ i ].key!=key;  - - i  );
 //不用for(i=n; i>0; - -i) 或 for(i=1; i<=n; i++)  
   return i; 
}

顺序查找的优缺点

优点:算法简单,对表结构无任何要求(顺序和链式)

缺点:n很大时查找效率较低

改进措施:非等概率查找时,可按照查找概率进行排序。

折半查找

折半查找又称为二分查找,它是一种效率高的一种查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中的元素按关键字有序排列。

其查找步骤为L:

1、设表长为n,low、high和mid分别指向待查元素所在区间的上界、下界和中点,key为给定值

2、初始时,令low=1,high=n,mid=(low+high)/2

3、让key与mid指向的记录比较

1>若key==R[mid].key,查找成功

2>若key<R[mid].key,则high=mid-1

3>若key>R[mid].key,则low=mid+1

4、重复上述操作,直至low>high时,查找失败

int Search_Bin(SSTable ST,KeyType key){
//若找到,则函数值为该元素在表中的位置,否则为0
    low=1;high=ST.length;					 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;                       		//后一子表查找
    }								  return 0;		//表中不存在待查元素
}					

折半查找的优缺点

折半查找优点:效率比顺序表查找高。

折半查找缺点:只适用于有序表,且限于顺序存储结构(对线性链表无效)。

查找过程:每次将待查记录所在区间缩小一半,比顺序查找效率高,时间复杂度O(log2 n)

哈希表的查找

基本思想:记录的存储位置与关键字之间存在对应关系,Loc(i)=H(keyi)

优点:查找速度极快O(1),查找效率与元素个数n无关。

散列表专业术语

1.哈希方法(杂凑法) :选取某个函数,依该函数按关键字计算元素的存储位置,并按此存放;  

  查找时,由同一个函数对给定值k计算地址,将k与地址单元中元素关键码进行比,确定查找是否成功。

2.哈希函数(杂凑函数):哈希方法中使用的转换函数。

3.冲 突:不同的关键码映射到同一个哈希地址。

4.同义词:具有相同函数值的两个关键字。

散列函数的构造方法

使用散列表要解决好两个问题:

1)构造好的散列函数

(a)所选函数尽可能简单,以便提高转换速度;

(b)所选函数对关键码计算出的地址,应在散列地址集中致均匀分布,以减少空间浪费。

2)制定一个好的解决冲突的方案

查找时,如果从散列函数计算出的地址中查不到关键码,则应当依据解决冲突的规则,有规律地查询其它相关单元。

除留取余法(最常用的方法)

Hash(key)=key  mod  p    (p是一个整数)

关键:如何选取合适的p?

技巧:设表长为m,取p≤m且为质数

 

 处理冲突的方法

开放地址法

基本思想:有冲突时就去寻找下一个空的哈希地址,只要哈希表足够大,空的哈希地址总能找到,并将数据元素存入。

其常用方法:

(1)线性探测法:di为1,2,3,4……m-1的线性序列;

(2)二次探测法:di为1^2,2^2,3^2……q^2 的二次序列;

(3)伪随机探测法:为伪随机数序列。

线性探测法

Hi=(Hash(key)+di) mod m( 1≤ i < m )

 其中:m为哈希表长度      

di 为增量序列 1,2,…m-1,且di=i(如果冲突就找下一空地址存入)

线性探测法优缺点

优点:只要哈希表未被填满,保证能找到一个空地址单元存放有冲突的元素。

缺点:可能使第i个哈希地址的同义词存入第i+1个地址,这样本应存入第i+1个哈希地址的元素变成了第i+2个哈希地址的同义词,……,产生“聚集”现象,降低查找效率。

链地址法

基本思想:相同哈希地址的记录链成一单链表,m个哈希地址就设m个单链表,然后用用一个数组将m个单链表的表头指针存储起来,形成一个动态的结构。

链地址法建立哈希表的方法步骤:

1、取数据元素的关键字key,计算其哈希函数值(地址)。若该地址对应的链表为空,则将该元素插入此链表;否则执行step2解决冲突。

2、根据选择的冲突处理方法,计算关键字key的下一个存储地址。若该地址对应的链表为不为空,则利用链表的前插法或后插法将该元素插入此链表。

链地址法的优点:

非同义词不会冲突,无“聚集”现象

链表上结点空间动态申请,更适合于表长不确定的情况

哈希表的查找

算法步骤:

1、给定待查找的关键字key,根据创建表时设定的散列函数计算H6= H(key)。

2、若单元H。为空,则所查元素不存在。

3、若单元H中元素的关键字为key,则查找成功。

4、否则重复下述解决冲突的过程:

按处理冲突的方法,计算下一个散列地址H;

若单元H为空,则所查元素不存在;

若单元H中元素的关键字为key,则查找成功。

#define NULLKEY 0
//单元为空的标记
int SearchHash (HashTable HT, KeyType key)
{//在散列表HT中查找关键字为key的元素,若查找成功,返回散列表的单元标号,否则返回-1
    HO=H(key) ;      //根据散列函数H( key )计算散列地址
    if (HT[H0] . key==NULLKEY) return -1;    //若单元H0为空,则所查元素不存在
    else if (HT[H0] .key==key) return H0;    //若单元HO中元素的关键字为key,则查找成功
    else
    {
        for(i=l;i<m;++i)
        {
            Hi= (H0+i) &m;    //按照线性探测法计算下一个散列地址Hi
            if (HT[Hi]. key--NULLKEY)return -1;//若单元H1为空,则所查元素不存在
            else if (HT[Hi] .key==-key) return Hi;//若单元出中元素的关键字为key,则查找成功
        }                                     //for
        return -1;
    }
}//else

使用平均查找长度ASL来衡量查找算法,ASL取决于

1、哈希函数 ;2、处理冲突的方法 ;3、哈希表的装填因子

 注:装填因子越大,表中记录数越多,说明表装得越满,发生冲突的可能性就越大,查找时比较次数就越多。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值