静态查找
顺序查找 折半查找 散列查找动态查找
二叉排序树 散列查找ASL(平均查找长度) - 衡量查找算法效率的主要指标
ASL=ΣPiCi;(1...n)
P为查找第i个元素的概率,Ci为查找到第i个元素所需的比较次数
顺序查找(线性查找)
注意:线性链表只能进行顺序查找;
typedef struct {
ElemType *data;
int TableLength;
}SSTable;
int Search_Seq(SSTable ST,ElemType key){
ST.data[0]=key;//哨兵 0号单元留空用来存哨兵
for(int i=ST.TableLength;ST.data[i]!-key;--i){
return i;
}
}
所以,
ASL(suc)=ΣPi * (n-i+1); (1...n)
ASL(fal)=ΣPi * (n+1); (1...n)
若查找概率相等为1/n;(Pi(suc)=1/n;Pi(fal)=1/n+1;)
ASL(suc)=(n+1)/2;
ASL(fal)=n+1;
对于有序表的顺序查找
ASL(suc)= (n+1)/2;
ASL(fal)=Qi * (Lj-1)=((n+1)/2 + n) /(n+1);(j为第j个失败结点)
化简得 =n/2+n/(n+1);
折半查找
要求:仅适用于有序顺序表
int Binary_Search(SeqList L,ElemType kay){
int low=0,high=L.TbaleLen-1,mid;
while(low<high){
mid=(low+high)/2;
if(L.data[mid]==key)
return mid;
else if(L.data[mid]<key)
high=mid-1;
else
low=mid+1;
}
return -1;
}
ASL=log(n+1)向上取整
可画二叉排序树进行判断 ,一般求ASL(成功)准确的为(每层的节点数 * 层数的和)/总结点数
ASL(失败)为(所有失败的节点 * 层数的和)/n+1;(这里失败的节点指的是树中2*N0+N1);
如图:
图中所有方形节点即为失败节点;
分块查找(索引顺序查找)
将表分块,块内可无序,块间有序
块间即索引表
ASL=Li+Ls;(Li索引查找,Ls块内查找)
长度为n的表分为b块,每块有s个记录;即(b=s/n)
Li=(b+1)/2;(b=s/n)
Ls=(s+1)/2
ASL=(s²+2s+n)/2s;
实际上对索引及块内记录的查找都为顺序查找,若为折半查找改为logn即可;
B树及B+树
其实对于B树,比较重要的几点:
B树的特性
对于一个m阶B树
1)每个结点最多m颗子树,(即至多含有m-1个关键字)
2)根节点不是终端节点时,则至少有两个子树
3)除根节点外所有的非叶节点,至少有ceil(m/2)颗子树,(即至少含有ceil(m/2)-1个关键字)
4)结点中关键字个数n(ceil(m/2)-1<=n<=m-1)
5)所有的叶结点出现在同一层上,且不带信息
所有结点的平衡因子均为0的多路查找树。
B树的高度(n为关键字个数)
n<=m^h-1;即 h>=logm(n+1);
n+1>=2(ceil(m/2))^(h-1);即h<=logceil(m/2)(n+1)/2 + 1;
B树上数据元素的增删调整,分裂方式很重要,我从中体会出的一点就是不管是增结点还是删除结点,首先判断关键字容量是否符合,符合就结束,不符合,就要分裂,分裂的情况中比较复杂的就是要和它的父结点发生变动的,像加个结点,有一个原则就是关键字超过上限了(m/2(向上取整)-1)就要分裂完全分开,两个的分成一个,多出来的上升为父结点,父结点关键字溢出则继续分裂上升从而最终结果就是这颗B树 长高了! 对于删除比较复杂的也是要从父结点借关键字的情况,(这个前提当然是在兄弟不够借的情况下)
B+树
这里只写与B树不同的地方,
3)结点的子树个数与关键字个数相同
4)所有叶结点包含全部的关键字按顺序排列,相邻结点同样也按顺序排列且互相链接起来
5)所有的分支结点中仅包含它的各个子结点中关键字最大的值及指向其子节点的指针
B+树种叶结点包含信息,所有非叶结点仅起到索引的作用 ,通常有两个头指针,一个只想最小的关键字,便于进行链式的顺序查找,另一个是根节点,便于进行多路查询。
Hash表
关于散列表比较重要的一块就是处理冲突的方法以及平均查找长度ASL
- 构造散列函数得到构造散列表
1)直接顶地址法
H(key)=a * k+b;
适合关键字分布基本连续,若分配不连续将造成空间浪费
2)除留余数法
散列表的长度为m,选一个不大于但接近m的质数p;
H(key)=key%p;
3)数字分析法
4)平方取中法
5)折叠法
一般构造函数题目中会直接给出,这块并不难
Hi=(H(key)+di)%m; - 处理冲突的办法
开放定地址发
1)线性探测
即冲突发生时,顺序查看表中下一个单元直到不冲突为止;
2)平方探测法(又称二次探测)
即di=1²,-1²,2²,-2²,.....,k²,-k²,k<=m/2;m必须为4k+3的质数
3)再散列法(双散列法)
di=Hash2(key);
即两个散列函数
4)伪随机序列
拉链法
将散列在同一地址的关键字用线性链表连接起来 - 散列查找性能分析
散列表的装填因子 α=表中记录长度n/散列表长度m;
散列表的平均查找长度依赖于散列表的装填因子,而不直接依赖于n或m。
查找成功的时的平均查找长度正常计算
查找失败时的平均查找长度为直到查找到第一个空结点为止,做经过的查找次数;
例如:拉链法为找到每一个同义词线性链的最后一个空结点;
散列表中为直到找到第一个表中元素为空的时候做经过的查找次数;