Funky's NoteBook

Search of Data Structure

字数统计: 1,810阅读时长: 7 min
2017/10/28 Share

查找

查找方法

  • 顺序查找
  • 折半查找
  • 分块查找

平均查找长度 ASL(Average Search Length )

所有查找过程中进行关键字比较次数的平均值
数学定义为:$ASL=\sum _{i=1}^n P_i C_i$

n是查找长度,$P_i$是查找第i个元素的概率,$C_i$是找到第i个元素所需进行比较次数

顺序查找

适用于无序的表,挨个查找

1
2
3
4
5
6
7
8
9
typedef struct {
ElemType *elem; //元素存储空间基址
int TableLen;//表长
}SSTable;
int Search_Seq(SSTable ST,ElemType key){
ST.elem[0]=key; //哨兵
for(i=ST.TableLen;ST.elem[i]!=key;--i); //从后往前找到i为0时退出for循环
return i;
}

平均查找长度:

折半查找

折半查找其实就是把查找表分成两半,然后在这两半里面继续分…

1
2
3
4
5
6
7
8
9
10
int BinarySearch(SeqList L;ElemType key){
int low=0,high=L.TableLen-1,mid;
while(low<high){
mid=(low+high)/2; //取中间位置
if(L.elem[mid]==key){return mid;} //查找成功则返回所在位置
else if(L.elem[mid]>key){high=mid-1;} //从前半部分查找
else {low=mid+1;} //从后半部分查找
}
return -1;
}

折半查找的过程可以用二叉树来描述,这个二叉树叫判定树,用折半查找到给定值的比较次数不会超过数的高度,即$\left \lceil log_2 (n+1) \right \rceil$

平均查找长度:
$ASL_{success}=log_2 (n+1)-1$

分块查找

分块查找又称索引查找,吸取了折半查找和顺序查找的优点,块内元素可以无序,但是块之间是有序的。
示意图:

索引表

24 54 78 88
1 7 10 13

查找表:

24* 21* 6* 11* 8* 22*

平均查找长度:
$ASL=L_I+L_S$

$L_I$ 和 $L_S$分别为索引查找和块内查找的平均查找长度

①若干将长度为n的产值表均匀分b块,每块s个记录,在等概率的情况下块内使用顺序查找那么平均查找长度为:$ASL=L_I+L_S=\frac{b+1}{2}+\frac{s+1}{2}$
②此时若$s=\sqrt{n}$,则平均查找长度取最小值:$\sqrt{n}+1$;若对索引表采用折半查找时,则平均查找长度为:$ASL=L_I+L_S=\left \lceil log_2(b+1)+\frac{s+1}{2} \right \rceil$

B树 & B+树

B树,又称多路平衡查找树,B树中所有节点的孩子节点数的最大值称为B数的阶,通常用m表示。一颗m阶的树或为空树,或为满足如下特性的树:
1、树中每个节点至多有m颗子树(即至多含有m-1个关键字)。
2、若根节点不是终端节点,则至少有两颗子树(至少一个关键字)。
3、除根节点外的所有非叶子节点至少有$\left \lceil m/2 \right \rceil$颗子树(即至少含有$\left \lceil m/2 \right \rceil-1$个关键字)。
4、所有的叶节点都出现在同一层次上,并且不带信息(实际这些节点并不存在,指向这些节点的指针为空)。

B树是所有节点的平衡因子均等于0的多路查找树

B树的高度(磁盘存储次数)

首先应该明确B树的高度不包括最后的不带任何信息的叶子节点那一层。

如果$n\geq 1$,则对任意一颗包含n个关键字、高度为h、阶数为m的B树:
有一棵树的高度:$h\geq log_m(n+1)$

如果让每个节点中的关键字个数达到最少则高度为:$h\leq log_{\left \lceil m/2 \right \rceil}(((n+1)/2)+1)$

B树的大部分操作所需的磁盘存取次数与B树的高度成正比

散列(Hash)表

散列函数:一个把查找表中的关键字映射成该关键字对应的地址的函数,记为Hash(key)=Addr。
散列函数块内会把两个或两个以上的不同关键字映射到同一个地址,这种情况称“冲突”,这些发生碰撞的不同关键字称为“同义词”。

散列表 是根据关键字而直接进行访问的数据结构。

散列函数的构造遵循规则

1.均匀分布,少冲突

2.计算简单,查找快

1.直接地址法

散列函数: H(key)=a*key+b

特点: 计算简单,不会产生冲突,适合连续存储的情况,但如果关键字分布不连续,空位较多,将造成存储空间浪费。

2.除留余数法

散列函数:H(key)=key%p
特点:简单、常用,使用关键是选好p,尽量减少冲突

3.数字分析法

设关键字是r进制数,而r个数码在各个位置上出现的频率不一定相同,在某些位上经常出现,则应选取数码分布较为均匀的若干位作为散列地址。

4.平方取中法

顾名思义,取关键字的平方值的中间几位作为散列地址:$10^{k-1} \leq n \leq 10^k $(其中n为集合中元素个数)

5.折叠法

将关键字分割成位数相同的几部分(最后一部分可以短一点),然后取这几部分的叠加作为散列地址。

处理冲突的方法

1.开地址法(闭散列法)

数学递推公式
$H_i=((H(key)+d_i)\%m)$
式中,$i=1,2,3,…,k(k \geq m-1 )$;m表示散列表表长;$d_i$为增量序列。

1) 线性探测法

不多说,冲突就往后挪,挪到有位置,停止

2) 平方探测法

当 $d_i = 1^2,-1^2,2^2,-2^2,…,k^2,-k^2,$其中$k \leq m/2 $,m必须是一个可以表示成4k+3的质数,又称二次探测法

3)再散列法

当 $d_i=Hash_2(Key)$, 如果第一个散列函数Hash(key)得到的地址发生冲突时,利用第二个散列函数计算该关键字的地址增量。再散列法经过m-1次探测会遍历表中的所有的位置,回到$H_0$位置。

4)伪随机序列法(简答题)

当$d_i$=伪随机序列,称为伪随机序列法。

注意在开放地址的情形下,不能随便物理删除所有元素,因为若删除元素将会截断其他具有相同散列地址元素的查找地址。所以若想删除一个元素时,给它做一个删除标记,进行逻辑删除。但副作用是,执行多次删除后,散列表表面上看起来很满,实际上有许多位置没用利用,因此需要定期维护散列表,要把删除标记的元素物理删除。

2.拉链法

假设散列地址为i的同义词链表的头指针存放在散列表的第i个单元中,因而查找、插入、删除都在同义词链中进行。

散列查找及性能分析

散列表的查找过程与构造散列表的过程基本一致。
装填因子:散列表的装填因子一般记为$\alpha$,定义为一个表的装满程度,即:
$\alpha =\frac{n}{m}$ 其中n为表中记录数,m为散列表长度。

CATALOG
  1. 1. 查找
    1. 1.1. 查找方法
    2. 1.2. 平均查找长度 ASL(Average Search Length )
    3. 1.3. 顺序查找
    4. 1.4. 折半查找
    5. 1.5. 分块查找
    6. 1.6. B树 & B+树
      1. 1.6.1. B树的高度(磁盘存储次数)
    7. 1.7. 散列(Hash)表
      1. 1.7.1. 散列函数的构造遵循规则
        1. 1.7.1.1. 1.直接地址法
        2. 1.7.1.2. 2.除留余数法
        3. 1.7.1.3. 3.数字分析法
        4. 1.7.1.4. 4.平方取中法
        5. 1.7.1.5. 5.折叠法
      2. 1.7.2. 处理冲突的方法
        1. 1.7.2.1. 1.开地址法(闭散列法)
          1. 1.7.2.1.1. 1) 线性探测法
          2. 1.7.2.1.2. 2) 平方探测法
          3. 1.7.2.1.3. 3)再散列法
          4. 1.7.2.1.4. 4)伪随机序列法(简答题)
        2. 1.7.2.2. 2.拉链法
    8. 1.8. 散列查找及性能分析