查找表的存储:线性表、索引结构、二叉树、哈希表
查找方法评价:
查找速度
占用存储空间的多少
算法本身复杂程度
平均查找长度ASL
- 一、线性表
typedef struct
{
int key;
Elemtype data;
}rectype;
rectype SeqList[n+1];
顺序查找算法
int search(rectype S[],int n,int k)
{
S[0].key=k;
int i=n;
while(S[i].key!=k){
i--;
}
return i;
}
有序表的查找:折半查找
要求:采用顺序存储结构的有序表
int binsrch(rectype S[],int n,int k)
{
int low,high,mid;
low=0;high=n-1;
while(low<=high){
mid=(low+high)/2;
if(S[mid].key==k)
return mid;
else if(S[mid].key<k)
low=mid+1;
else
high=mid-1;
}
return -1;
}
描述折半查找过程的二叉树叫判定树。
查找某个结点所比较的次数等于该结点的层次数
查找成功时进行比较的次数最多不超过树的深度
索引表上的查找
查找过程:将表分成几块,块内无序,块间有序;先确定待查记录所在块,再在块内查找
适用条件:分块有序表
查找方法比较
- 二、动态查找表
表结构在查找过程中动态生成
对于给定值key
1.若表中存在其关键字等于key的记录,则查找返回成功
2.否则插入关键字等于key的记录
二叉排序树
二叉排序树定义:
二叉排序树(Binary Sort Tree)或者是一棵空二叉树;或者具有下列性质的二叉树:
A. 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
B. 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
C. 它的左右子树也分别为二叉排序树。
实际上,折半查找法的判定树就是一棵二叉排序树。
查找思想
首先将给定的K值与二叉排序树的根结点的关键字进行比较:
(a)若相等: 则查找成功;
(b)给定的K值小于BST的根结点的关键字:继续在该结点的左子树上进行查找;
(c)给定的K值大于BST的根结点的关键字:继续在该结点的右子树上进行查找。
void InsertBitree(BiTree &T,int k)//二叉排序树的插入
{
BiTree s;
s=(BiTree)malloc(sizeof(BiNode));
s->key=k;s->lchild=s->rchild=NULL;
if(T==NULL)T=s;
else{
if(T->key>k)
InsertBitree(T->lchild,k);
else if(T->key<k)
InsertBitree(T->rchild,k);
}
}
BiTree BSTsearch(BiTree T,int key)//二叉排序树的搜索
{
if(T){
if(T->key<key)
return(BSTsearch(T->rchild,key));
else if(T->key>key)
return (BSTsearch(T->lchild,key));
else
return T;
}
return NULL;
}
A.中序遍历可以得到一个关键字的有序序列,这就是说,一个无序序列可以通过构造一棵二叉排序树而变成一个有序序列。
B.每次插入的新结点都是树中一个叶子结点,因此在进行插入的时候不必移动其他结点,仅需改动某个结点的指针。相当于在一个有序序列上插入一个记录而不需要移动其他记录。
二叉排序树结点的删除
void Delete(BiTree &p)
{
BiTree q,s;
if(!(p->lchild)&&!(p->rchild))//删除叶子结点
p=NULL;
else if(!(p->lchild)){//无左孩子
q=p;
p=p->rchild;
free(q);
}
else if(!(p->rchild)){//无右孩子
q=p;
p=p->lchild;
free(q);
}
else{//同时具有左右孩子,选择第二种删除方法
q=p;
s=p->lchild;
while(s->rchild){
q=s;
s=s->rchild;
}
p->key=s->key;
if(q!=p)
q->rchild=s->lchild;
else
q->lchild=s->lchild;
free(s);
}
}
void BSTdelete(BiTree &T,int key)
{
if(T){
if(T->key<key)
BSTdelete(T->rchild,key);
else if(T->key>key)
BSTdelete(T->lchild,key);
else
Delete(T);
}
}
平衡二叉树AVL
1、定义:
平衡二叉树或者是空树,或者是满足下列性质的二叉树。
⑴左子树和右子树深度之差的绝对值不大于1;
⑵左子树和右子树也都是平衡二叉树。
2、平衡因子(BF) :二叉树上结点的左子树的深度减去其右子树深度称为该结点的平衡因子。
3、性质:平衡二叉树上每个结点的平衡因子只可能是-1、0和1。
4、平衡二叉排序树:如果一棵二叉树既是二叉排序树又是平衡二叉树,称为平衡二叉排序树。
5、平衡二叉排序树的ASL与logn同数量级。
构造平衡二叉树
平衡化旋转有两类:
单旋转 (左旋和右旋)
双旋转 (左平衡和右平衡)
每插入一个新结点时, AVL 树中相关结点的平衡状态会发生改变。因此, 在插入一 个新结点后,需要从插入位置沿着通向根的路径回溯,检查各结点的平衡因子。
- 三、哈希表
基本思想:在记录的存储地址和它的关键字之间建立一个确定的对应关系;
散列函数:使每个关键码都和结构中存储位置对应,这样的一个对应关系称为散列(哈希Hash)函数。
2.散列(哈希)表:应用哈希函数,由记录的关键字确定记录在表中的地址,并将记录放入此地址,这样构成的表叫~
3.散列查找:又叫哈希查找,利用哈希函数进行查找的过程叫~
4.冲突(碰撞):key1!=key2,但H(key1)==H(key2)的现象叫~
5.同义词:具有相同函数值的两个关键字,叫该哈希函数的~
6.装填因子(负载因子):
α=表中的记录数/哈希表长度
α>1时,冲突不可避免
常用的构造散列函数的方法有:
1.直接地址法
取关键字或关键字的某个线性函数值为哈希地址:
H(key)=key或H(key)=a×key+b
2.(特征位抽取法)数字分析法
3.平方取中法
4.折叠法
5.除留余数法
构造:取关键字被某个不大于哈希表表长m的数p除后所得余数作哈希地址,即H(key)=key%p,p<=m (一般选取p<=m 的最大素数)
哈希冲突解决方法
1.开放地址法(闭散列方法)
在基本区域内形成一个探查序列
Hi = (H(key) + di)% m, i = 1, 2, …, k ( k <=m-1)
其中:m为表长,di为增量序列,可有多种取法:
A. di = 1, 2, 3, …, m-1, 称线性探查序列;
B. di = 12, -12, 22, -22, …, k2, -k2 (k <= m/2),称为二次探查序列;
C. di = i*h2(key), h2(key)是另一个散列函数,称双散列探查序列;(h2(key)=key%(p’)+1,其中p‘< p的素数)
线性探测法的特点
优点:只要散列表未满,总能找到一个不冲突的散列地址;
缺点:每个产生冲突的记录被散列到离冲突最近的空地址上,从而又增加了更多的冲突机会(这种现象称为冲突的“聚集”)。
开散列法
方法:将所有关键字为同义词的记录存储在一个单链表中,并用一维数组存放头指针
查找比较
(1)顺序表示
A.顺序检索:简单,常用于未排序元素的检索,但检索效率不高;
B.二分法检索:仅用于排序元素,检索效率较高当插入、删除运算时会引起大量数据的移动。
(2)散列表示:
检索操作达到近乎随机存取的速度。但散列表示经常出现碰撞与堆积现象,增加了检索长度。
(3)二叉树表示—二叉排序树:
元素插入次序不同,会构成不同的二叉排序树。最佳二叉排序树的平均检索长度为O(log2n) 。