一、查找的基本概念
1)查找表
查找表是由同一类型的数据元素或记录构成的集合。
2)关键字
关键字是数据元素或记录中某个数据项的值,用它可以标识一个数据元素或记录;
若一个关键字可以唯一地标识一个记录,则称之为主关键字;反之,称用以识别若干记录的关键字为次关键字。
当数据元素只有一个数据项时,其关键字为该数据元素的值。
3)查找
查找是指根据给定的某个值,在查找表中确定一个其关键字等于给定值的记录或数据元素。若表中存在这样一个记录,则称查找成功,否则称查找不成功。
4)动态查找表和静态查找表
若在查找的同时对表做修改操作(如插入和删除),则相应的表称之为动态查找表,否则称之为静态查找表。
5)平均查找长度(ASL)
为确定记录在查找表中的位置,需和给定值进行比较的关键字个数的期望值,称为查找算法在查找成功时的平均查找长度。
Pi为查找表中第i个记录的概率,且
Ci为找到表中其关键字与给定值相等的第i个记录时,和给定值已进行过比较的关键字个数。
二、线性表的查找
1)顺序查找(Sequential Search)
查找过程:按顺序从表的一端向另一端查找,依次将表中记录的关键字和给定值进行比较,若某个表中值和给定值相等,则查找成功;反之,若整个表扫描完毕也未找到和给定值相等的记录,则查找失败。
顺序查找适用于线性表的顺序存储结构和链式存储结构。
顺序表的数据结构:
typedef struct{
Elemtype *R; //存储空间基地址
int length; //当前长度
}
1.一般的顺序查找算法
int Search_seq(SStable ST,KeyType key){
for(i=ST.length;i>=1;--i){ //从后往前找
if(ST.R[i].key==key) return i;
}
return 0; //未找到则返回0
}
2.设置监视哨的顺序查找算法
把查找的最后一位设为给定值,免去了每次判断是否越界的问题
int Search_seq(SStable ST,KeyType key){
ST.R[0].key=key; //“哨兵”
for(i=ST.length;ST.R[i].key!=key;--i){ //从后往前找
if(ST.R[i].key!=key) return i;
}
return 0;
}
算法分析:
时间复杂度:O(n);
优点:简单,对表结构无任何要求;
缺点:平均查找长度较大,查找效率低。
2)折半查找(Binary Search)
也称二分查找,要求线性表必须采用顺序存储结构,且表中元素按关键字有序排列。
查找过程:从表的中间记录开始,如果给定值和中间记录的关键字相等,则查找成功;如果给定值大于或者小于中间记录的关键字,则在表中大于或小与中间记录的那一半中查找,这样重复操作,直到查找成功,或者在某一步中查找区间为空,则代表查找失败。
折半查找算法
//以low和high来表示当前查找区间的下界和上界,mid为区间的中间位置
int Search_Bin(SStable ST,KeyType key){
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; //查找失败
}
算法分析:
折半查找过程可用二叉树来描述。树中每一结点对应表中一个记录,但结点值不是记录的关键字,而是记录在表中的位置序号。把当前查找区间的中间位置作为根,左子表和右子表分表作为根的左子树和右子树,由此得到的二叉树称为折半查找的判定树。
成功的折半查找恰好是走了一条从判定树的根到被查结点的路径,精力比较的关键字个数恰为该结点在树中的层次,由此可计算折半查找的平均查找长度:以长度为11的有序表为例,
一般情况下,n较大时,有 (可以以满二叉判定树为例计算出)
因此,折半查找的时间复杂度:O(log2(n));
优点:比较次数少,查找效率高;
缺点:对表结构要求高,只能用于顺序存储的有序表。查找前需要排序,而排序本身也费时。同时,折半查找也不适用于数据元素经常变动的线性表,因为为保持顺序表的有序性,插入和删除操作平均要比较和移动表中一半元素。
3)分块查找(Blocking Search)
又称索引顺序查找,性能介于顺序查找和折半查找之间。分块查找是将表中记录分成几个子表(或称块),对每个子表建立一个索引项,包括该子表的最大记录以及第一个记录在表中的位置,各个子表的索引项组成一个索引表,索引表中“分块有序”,如第二个子表的最小值大于第一个子表的最大值,以此类推。查找时先确定待查记录所在的块(子表),然后在块中顺序查找。
算法分析:
确定块的查找可以用顺序查找或折半查找,在块中只能用顺序查找,分块查找中
优点:由于块内无序,插入删除比较容易;
缺点:要增加一个索引表的存储空间,并对初始索引表进行排序运算。
注:本文所有内容均来源于《数据结构(C语言第二版)》(严蔚敏老师著)