查找
查找表: 是由同一类型的数据元素(或记录)构成的集合。
查找表的操作:
(1)查询某个“特定的”数据元素是否在查找表中。
(2)检索某个“特定的”数据元素的各种属性。
(3)在查找表中插入一个数据元素;
(4)从查找表中刪去某个数据元素。
静态查找表:对查找表只作前两种操作
动态查找表:在查找过程中查找表元素集合动态改变
关键字:是数据元素(或记录)中某个数据项的值
主关键字:可以唯一的地标识一个记录
次关键字:用以识别若干记录
查找:根据给定的某个值,在查找表中确定一个其关键字等于给定的记录或数据元素。若表中存在这样的一个记录,则称查找是成功的,此时查找的结果为给出整个记录的信息,或指示该记录在查找表中的位置;若表中不存在关键字等于给定值的记录,则称查找不成功。
一些约定:
典型的关键字类型说明:
typedef float KeyType;//实型
typedef int KeyType;//整型
typedef char *KeyType;//字符串型
数据元素类型定义为:
typedef struct{
KeyType key; // 关键字域
...
}ElemType;
对两个关键字的比较约定为如下的宏定义:
对数值型关键字
#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a)<(b))
#define LQ(a,b) ((a)<=(b))
对字符串型关键字
#define EQ(a,b) (!strcmp((a),(b)))
#define LT(a,b) (strcmp((a),(b))<0)
#define LQ(a,b) (strcmp((a),(b))<=0)
1、静态查找表
静态查找表的类型定义:
ADT StaticSearchTable{
数据对象D:D是具有相同特性的数据元素的集合。各个数据元素均含有类型相同,可唯一标识数据元素的关键字。
数据关系R:数据元素同属一个集合。
基本操作P:
Create(&ST,n);
操作结果:构造一个含n个数据元素的静态查找表ST。
Destroy(&ST);
初始条件:静态查找表ST存在。
操作结果:销毁表ST。
Search(ST,key);
初始条件:静态查找表ST存在,key为和关键字类型相同的给定值。
操作结果:若ST中在在其关键字等于key的数据元素,则函数值为该元素的值或在表中的位置,否则为“空”。
Traverse(ST,Visit());
初始条件:静态查找表ST存在,Visit是对元素操作的应用函数。
操作结果:按某种次序对ST的每个元素调用函数visit()一次且仅一次。一旦visit()失败,则操作失败。
}ADT StaticSearchTable
1.1、顺序表的查找
以顺序表或线性链表表示静态查找表,则Search函数可以顺序查找来实现
静态查找表的顺序存储结构
typedef struct {
ElemType *elem;
int length;
}SSTable;
顺序查找:从表中最后一个记录开始,逐个进行记录的关键字和给定值的比较,若某个记录的关键字和给定值比较相等,则查找成功,找到所查记录;反之,查找不成功。
int Search_Seq( SSTable ST ,KeyType key){
ST.elme[0].key=key;
for(i=ST.length; !EQ(ST.elem.key,key); --i);
return i;
}
查找操作的性能分析:
查找算法中的基本操作是将记录的关键字和给定值进行比较,通常以“其关键字和给定值进行过比较的记录个数的平均值”作为衡量依据。
平均查找长度:为确定记录在查找表中的位置,需用和给定值进行比较的关键字个数的期望值称为查找算法在查找成功时的平均查找长度。
查找成功时的平均查找长度:
查找不成功时的平均查找长度:
1.2、有序表的查找
以有序表表示静态查找表时,Search函数可用折半查找来实现
折半查找的查找过程:先确定待查记录所在的范围,然后逐步缩小范围直到找到或找不到该记录为止。
折半查找的查找实现:
int Search_Bin( SSTable ST ,KeyType key){
low=1;high=ST.length;
while(low<=high){
mid=(low+high)/2;
if EQ(key,ST.elem[mid].key) return mid;
else if LT(key,ST.elem[mid].key) high=mid -1;
else low=mid +1 ;
}
return 0;
}//Search_Bin;
查找成功时的平均查找长度:
1.3、索引顺序表的查找
若以索引顺序表表示静态查找表,则Search函数可用分块查找来实现
分块查找又称为索引顺序查找,是顺序查找的一种改进方法。在此查找法中,除表本身以外,尚需建立一个“索引表”。表中的记录可以划分为多个子表,对每个子表建立一个索引项,其中包括两项内容:关键字项(其值为该子表内的最大关键字)和指针项(指示该子表中的第一个记录在表中位置)。索引表按关键字有序,查找表或者有序或者分块有序。
分块查找过程分为两步进行:先确定待查记录所在的块(子表),然后在块中顺序查找
由于由索引项组成的索引表按关键字有序,则确定块的查找可以用顺序查找,亦可用折半查找,而块中的记录是任意排列的,则在块中只能是顺序查找
2、动态查找表
动态查找表的特点是:表结构本身是在查找过程中动态生成的,即对于给定值key,若表中存在其关键字等于key的记录,则查找成功返回,否则插入关键字等于key的记录。
动态查找表的定义:
ADT DymanicSearchTable{
数据对象D:D是具有相同特性的数据元素的集合。各个数据元素均含有类型相同,可唯一标识数据元素的关键字。
数据关系R:数据元素同属一个集合。
基本操作P:
InitDSTable(&DT);
DestroyDSTable(&DT);
SearchDSTable(DT,key);
InsertDSTable(&DT,e);
DeleteDSTable(&DT,key);
TraverseDSTable(DT,Visit());
}ADT DynamicSearchTable
2.1、二叉排序树和平衡二叉树
2.1.1 、二叉排序树及其查找过程
二叉排序树或者是一棵空树;或者是具有下列性质的二叉树:
(1)若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)它的左、右子树了分别为二叉排序树。
如果取二叉链表作为二叉排序树的存储结构,则上述查找过程如下:
BiTree SearchBST(BiTree T,KeyType key){
if(!T)||EQ(key,T->data.key)) return (T);
else if LT(key,T->data.key) return (SearchBST(T->lchild,key));
else return (SearchBST(T->rchild.key));
}//SearchBST
2.1.2 、二叉排序树的插入和删除
二叉排序树是一种动态树表,其特点是,树的结构通常不是一次生成的,而是在查找过程中,当树中不存在关键字等于给定值的结点时再进行插入。新插入的结点一定是一个新添加的叶子结点,并且是查找不成功时查找路径上访问的最后一个结点的左孩子或右孩子结点。
Status SearchBST(BiTree T,KeyType key,BiTree f,BiTree &p){
if(!T) {p=f;return FALSE;}
else if EQ(key,T->data.key){ p=T;return TRUE;}
else if LT(key,T->data.key) SearchBsT(T->lchild,key,T,p);
else SearchBST(T->rchild,key,T,p);
}//SearchBST
插入算法:
Status InsertBST(BiTree &T,ElemType e){
if(!SearchBST(T,e.key,NULL,p){
s=(BiTree)malloc(sizeof(BiTNode));
s->data=e;s->lchild=s->rchild=NULL;
if(!p) T=s;
else if (LT(e.key,p->data.key) p->lchild=s;
else p->rchild=s;
return TRUE;
}
else return FALSE;
}//InsertBST
对于二叉排序树,删去树上一个结点相当于删去有序序列中的一个记录,要在删除某个节点之后依旧保持二叉排序树的特性。
二叉排序树的删除操作可分三种情况进行处理:
1)*P是叶子,则直接删除*P,即将*P的双亲*parent 中指向*P的指针域置空即可。
2)*P只有一个孩子*child,此时只需将*child和*p的双亲直接连接就可删去*p.
3)*p有两个孩子,则将操作转换成删除*p结点的中序后继,在删去它之前把这个结点的数据复制到原来要删的结点位置上就完成了删除。
3、哈希表
3.1、哈希表的概念及作用
一般的线性表,树中,记录在结构中的相对位置是随机的,即和记录的关键字之间不存在确定的关系,因此,在结构中查找记录时需进行一系列和关键字的比较。这一类查找方法建立在“比较“的基础上,查找的效率依赖于查找过程中所进行的比较次数。
理想的情况是能直接找到需要的记录,因此必须在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使每个关键字和结构中一个唯一的存储位置相对应。在查找时,只要根据这个对应关系f找到给定值K的像f(K)。若结构中存在关键字和K相等的记录,则必定在f(K)的存储位置上,由此,不需要进行比较便可直接取得所查记录。在此,我们称这个对应关系f为哈希函数,按照这个思想建立的表为Hash表