查找
查找的基本概念
1.查找表
查找表是由同一类型的数据元素(或记录)构成的集合。由于“集合”中的数据元素之间存在着完全松散的关系,因此查找表是一种非常灵便的数据结构,可以利用其他的数据结构来实现,比如本章将要介绍的线性表、树表及散列表等。
2.关键字
关键字是数据元素(或记录)中某个数据项的值,用它可以标识一个数据元素(或记录)。若此关键字可以唯一地标识一个记录,则称此关键字为主关键字(对不同的记录,其主关键字均不同)。反之,称用以识别若干记录的关键字为次关键字。当数据元素只有一个数据项时,其关键字即该数据元素的值。
3.查找
查找是指根据给定的某个值,在查找表中确定一个其关键字等于给定值的记录或数据元素。若表中存在这样的一个记录,则称查找成功,此时查找的结果可给出整个记录的信息,或指示该记录在查找表中的位置;若表中不存在关键字等于给定值的记录,则称查找不成功,此时查找的结果可给出一个“空”记录或“空”指针。
4.动态查找表和静态查找表
若在查找的同时对表执行修改操作(如插入和删除),则称相应的表为动态查找表,否则称之为静态查找表。换句话说,动态查找表的表结构本身是在查找过程中动态生成的,即在创建表时,对于给定值,若表中存在其关键字等于给定值的记录,则查找成功并返回;否则插入关键字等于给定值的记录。
5.平均查找长度(ASL)
在查找的过程中,一次查找的长度是指需要比较的关键字次数,而平均查找长度则是所有查找过程中进行关键字的比较次数的平均值。
n:记录的个数
pi:查找第i个记录的概率 ( 通常认为pi =1/n )
ci:找到第i个记录所需的比较次数
顺序查找
1.应用范围
顺序表或线性链表表示的静态查找表
2.顺序表的表示
typedef struct{
ELemType *R; //储存空间基地址
int length; //当前长度
}SSTable;
3.数据元素类型的定义
typedef struct{
KeyType key; // 关键字域
InfoType otherinfo; //其他域
}ElemType;
4.顺序查找的实现
int Search_Seq(SSTable ST,KeyType key)
{ /*在顺序表ST中顺序查找其关键字等于key的数据元素。若找到
就返回该数据元素在表中的位置*/
for(i=ST.length;i>=1;i--){ //从后往前找
if(ST.R[i].key==key)
return i
}
return 0;
}
5.性能分析
查找成功时的平均查找长度(设表中各记录查找概率相等):ASL=(1+2+ … +n)/n =(n+1)/2
查找不成功时的平均查找长度:ASL =n+1
6.特点
算法简单,对表结构无任何要求(顺序和链式)。
n很大时,平均查找长度较大,查找效率较低。
折半查找
折半查找(Binary Search)也称二分查找,它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。在下面及后续的讨论中,均假设有序表是有序递增的。
折半查找的查找过程为:从表的中间记录开始,如果给定值和中间记录的关键字相等,则查找成功;如果给定值大于或者小于中间记录的关键字,则在表中大于或小于中间记录的那一半中查找,这样重复操作,直到查找成功,或者在某一步中查找区间为空,则代表查找失败。
折半查找每一次查找都使查找范围缩小一半,与顺序查找相比,很显然会提高查找效率。为了标记查找过程中每一次的查找区间,下面分别用low和high来表示当前查找区间的下界和上界,mid为区间的中间位置。
算法思想:
1.将待查找元素x的关键字x.key与查找表中间位置数据元素的关键字(a mid.key)比较
2.如果等于给定值,则查找成功,返回成功值;
若大于给定值,在表的左部继续折半查找
若小于给定值,在表的右部继续折半查找
3.仅当左部或右部为空,查找失败,返回失败值
算法实现:
int Search_Bin(SSTable ST,KetType key){
/*在有序表中ST中折半查找其关键字等于key的数据元素。
若找到,则函数值为该元素在表中的位置*/
low=1;
height=ST.length;
while(low<=height){
mid=(low+height)/2;
if(key==ST.R[mid].key)
return mid;
else if(key<ST.R[mid].key)
height=mid-1;
else low=mid+1;
}
return 0;
}
散列表的查找
散列技术是在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key)。建立了关键字与存储位置的映射关系。
采用散列技术将记录存在在一块连续的存储空间中,这块连续存储空间称为散列表或哈希表。那么,关键字对应的记录存储位置称为散列地址。
散列技术既是一种存储方法也是一种查找方法。散列技术的记录之间不存在什么逻辑关系,它只与关键字有关,因此,散列主要是面向查找的存储结构。
散列表的储存表示:
#define m 20 //散列表表长
typedef struct{
KeyType key; //关键字项
InfoType otherinfo; //其他数据项
}HashTable[m];
算法步骤:
给定待查找的关键字key,根据创建表时设定的散列函数计算H0=H(key)
若单元H0为空,则所查元素不存在。
若单元H0的中元素的关键字为key,则查找成功。
否则重复下述解决冲突的过程:
按处理冲突的方法,计算下一个散列地址H;
若单元H0为空,则所查元素不存在;
若单元H0;中元素的关键字为key,则查找成功。
算法实现:
#define NULLKEY 0
int SearchHash(HashTable HT,KeyType key){
H0=H(key);
if(HT[H0].key==NULLKEY)
return -1;
else if(HT[H0].key==key)
return H0;
else{
for(i=1;i<m;++i){
Hi=(H0+i)%m;
if(HT[H0].key==NULLKEY)
return -1;
else if(HT[H0].key==key)
return Hi;
}
return -1;
}
}