@@ -38,7 +38,7 @@ ASL查找失败为$\dfrac{1+2+3+\cdots+n+n}{n+1}=\dfrac{n}{2}+\dfrac{n}{n+1}$。
#### 折半查找的结构
定义三个指针, low指向查找范围的最小值, high指向查找范围的最大值, mid指向查找范围的中间值, $mid=\lfloor(low+high)/ 2\rfloor$。(也可以向上取整,过程会有所不同)
定义三个指针, low指向查找范围的最小值, high指向查找范围的最大值, mid指向查找范围的中间值, $mid=\lfloor(low+high)\div 2\rfloor$。(也可以向上取整,过程会有所不同)
#### 折半查找的过程
@@ -94,7 +94,7 @@ ASL查找成功失败的情况都十分复杂, 所以一般不会考。
#### B树的定义
为了保证m叉查找树中每个结点都能被有效利用, 避免大量结点浪费导致树高过大, 所以规定m叉查找树中, 除了根结点以外, 任何结点至少有$\lceil m/2 \rceil$个分叉,即至少包含$\lceil m/2 \rceil-1$个结点。
为了保证m叉查找树中每个结点都能被有效利用, 避免大量结点浪费导致树高过大, 所以规定m叉查找树中, 除了根结点以外, 任何结点至少有$\lceil\dfrac{m}{2} \rceil$个分叉,即至少包含$\lceil\dfrac{m}{2} \rceil-1$个结点。
为了保证m叉查找树是一棵平衡树, 避免树偏重导致树高过大, 所以规定m叉查找树中任何一个结点, 其所有子树的高度都要相同。
@@ -107,7 +107,7 @@ B树即多路平衡查找树, 所有结点的孩子个数的最大值就是B树
+ 树的每个结点至多包含m棵子树, 至多包含m-1个关键字。
+ B树最底端的失败的不存在的结点就是常说的叶子结点, 而最底端的存在数据的结点就是终端结点。( 一般的树的叶子结点和终端结点都是指最底端的有数据的结点)
+ 若根结点不是终端结点,则至少有两颗子树,任意结点的每棵子树都是绝对平衡的。
+ 除根结点以外的所有非叶结点至少有$\lceil m/2 \rceil$棵子树,即至少包含$\lceil m/2 \rceil-1$个结点。
+ 除根结点以外的所有非叶结点至少有$\lceil\dfrac{m}{2} \rceil$棵子树,即至少包含$\lceil\dfrac{m}{2} \rceil-1$个结点。
+ 所有叶结点都出现在同一个层次上且不带信息。
+ 每个结点中的关键字是有序的。子树0 < 关键字1 < 子树2 < ...。
@@ -115,14 +115,14 @@ B树即多路平衡查找树, 所有结点的孩子个数的最大值就是B树
+ 最小高度:让每个结点尽可能满,有$m-1$个关键字,$m$个分叉,则一共有$(m-1)(m^0+m^1+m^2+\cdots+m^{h-1})$个结点,其中$n$小于等于这个值,从而求出$h\geqslant\log_m(n+1)$。
+ 最大高度:
+ 让各层分叉尽可能少,即根结点只有两个分叉,其他结点只有$\lceil m/2 \rceil$个分叉, 所以第一层1个, 第二层2个, 第$h$层$2(\lceil m/2 \rceil)^{h-2}$个结点,而$h+1$层的叶子结点有$2(\lceil m/2 \rceil)^{h-1}$个,且$n$个关键字的B树必然有$n+1$个叶子结点,从而$n+1\geqslant2(\lceil m/2 \rceil)^{h-1}$,即$h\leqslant\log_{\lceil m/2 \rceil}\dfrac{n+1}{2}+1$。
+ 让各层关键字尽可能少,记$k=\lceil m/2 \rceil$。第一层最少结点数和最少关键字为1; 第二层最少结点数为2, 最少关键字为$2(k-1)$,第三层最少结点数为$2k$,最少关键字为$2k(k-1)$,第$h$层最少结点数为$2k^{h-2}$,最少关键字为$2k^{h-2}(k-1)$,从而$h$层的m阶B数至少包含关键字总数$1+2(k-1)(k^0+k^1+\cdots+k^{h-2})=1+2(k^{h-1}-1)$,若关键字总数小于这个值,则高度一定小于$h$,所以$n\geqslant 1+2(k^{h-1}-1)$,则$h\leqslant\log_{\lceil m/2 \rceil}\dfrac{n+1}{2}+1$。
+ 让各层分叉尽可能少,即根结点只有两个分叉,其他结点只有$\lceil\dfrac{m}{2} \rceil$个分叉, 所以第一层1个, 第二层2个, 第$h$层$2(\lceil\dfrac{m}{2} \rceil)^{h-2}$个结点,而$h+1$层的叶子结点有$2(\lceil\dfrac{m}{2} \rceil)^{h-1}$个,且$n$个关键字的B树必然有$n+1$个叶子结点,从而$n+1\geqslant2(\lceil\dfrac{m}{2} \rceil)^{h-1}$,即$h\leqslant\log_{\lceil\dfrac{m}{2} \rceil}\dfrac{n+1}{2}+1$。
+ 让各层关键字尽可能少,记$k=\lceil\dfrac{m}{2} \rceil$。第一层最少结点数和最少关键字为1; 第二层最少结点数为2, 最少关键字为$2(k-1)$,第三层最少结点数为$2k$,最少关键字为$2k(k-1)$,第$h$层最少结点数为$2k^{h-2}$,最少关键字为$2k^{h-2}(k-1)$,从而$h$层的m阶B数至少包含关键字总数$1+2(k-1)(k^0+k^1+\cdots+k^{h-2})=1+2(k^{h-1}-1)$,若关键字总数小于这个值,则高度一定小于$h$,所以$n\geqslant 1+2(k^{h-1}-1)$,则$h\leqslant\log_{\lceil\dfrac{m}{2} \rceil}\dfrac{n+1}{2}+1$。
#### B树的插入
新元素插入一定是插入到最底层的终端结点, 使用B树的查找来确定插入位置。
若导致原结点关键字数量超过上限溢出,就从中间位置$\lceil m/2 \rceil$分开,将左部分包含的关键字放在原来结点,右部分包含的关键字放在一个新结点,并插入到原结点的父结点的后一个位置上,而在原结点的父结点连接后的结点后移一个连接让位给分割出来的右半部分结点,中间的一个结点$\lceil m/2 \rceil$插入到原结点的父结点上,并考虑在父结点的顺序。
若导致原结点关键字数量超过上限溢出,就从中间位置$\lceil\dfrac{m}{2} \rceil$分开,将左部分包含的关键字放在原来结点,右部分包含的关键字放在一个新结点,并插入到原结点的父结点的后一个位置上,而在原结点的父结点连接后的结点后移一个连接让位给分割出来的右半部分结点,中间的一个结点$\lceil\dfrac{m}{2} \rceil$插入到原结点的父结点上,并考虑在父结点的顺序。
若父结点插入时也溢出了,则同理在父结点的中间进行分割,左半部分在原来父结点;右半部分新建一个父结点,并把中间结点右边开始的所有连接移动到新父结点上;中间的结点上移到祖父结点,如果没有就新建,然后建立两个指针分别指向原父结点和新父结点。
@@ -159,7 +159,7 @@ B+树考的并不是很深。
一个m阶的B+树需要满足以下条件:
1. 每个分支结点最多有m棵子树或孩子结点。
2. 为了保持绝对平衡,非叶根结点至少有两棵子树,其他每个分支结点至少有$\lceil m/2 \rceil$棵子树。( 不同于B树, B+树又重新将最下面的保存的数据定义为叶子结点)
2. 为了保持绝对平衡,非叶根结点至少有两棵子树,其他每个分支结点至少有$\lceil\dfrac{m}{2} \rceil$棵子树。( 不同于B树, B+树又重新将最下面的保存的数据定义为叶子结点)
3. 结点的子树个数与关键字个数相等。( B树结点子为树个数与关键字个数加1)
4. 所有叶结点包含所有关键字以及指向记录的指针, 叶结点中将关键字按大小排序, 并且相邻叶子结点按大小顺序相互连接起来。所以B+树支持顺序查找。
5. 所有分支结点中仅包含其各子结点中关键字的最大值以及指向其子结点的指针(即分支结点只是索引)。
@@ -180,7 +180,7 @@ B+树可以顺序查找,在叶子结点的块之间定义指向后面叶子结
:--:|:--:|:--:
结点的n个关键字对应的子树个数|$n$|$n+1$
根结点的关键字数|$[1,m]$|$[1,m-1]$
其他结点的关键字数|$[\lceil m/2 \rceil,m]$|$[\lceil m/2 \rceil-1,m-1]$
其他结点的关键字数|$[\lceil\dfrac{m}{2} \rceil,m]$|$[\lceil\dfrac{m}{2} \rceil-1,m-1]$
关键字分布|叶子结点包含所有关键字,非叶结点包含部分重复关键字|所有结点的关键字不重复
结点作用|叶子结点包含信息,非叶子结点是索引作用|所有结点都包含信息
结点存储内容|叶子结点包含关键字与对应记录的存储地址,非叶子结点包含对应子树的最大关键字和指向该子树的指针|所有结点都包含关键字与对应记录存储地址
@@ -197,7 +197,7 @@ B+树可以顺序查找,在叶子结点的块之间定义指向后面叶子结
关键字与地址通过散列函数(哈希函数)来实现映射。即记录位置=散列函数(记录关键字)。
+ 直接定址法:可表示为散列函数(关键字)=a* 关键字+b, 其中a、b均为常数。这种方法计算特别简单, 并且不会发生冲突, 但当关键字分布不连续时, 会出现很多空闲单元, 会将造成大量存贮单元的浪费。
+ 直接定址法:可表示为散列函数(关键字)=a× 关键字+b, 其中a、b均为常数。这种方法计算特别简单, 并且不会发生冲突, 但当关键字分布不连续时, 会出现很多空闲单元, 会将造成大量存贮单元的浪费。
+ 数字分析法:分析关键字的各个位的构成,截取其中若干位作为散列函数值,尽可能使关键字具有大的敏感度,即最能进行区分的关键字位,这些位数都是连续的。
+ 平方取中法:先求关键字的平方值,然后在平方值中取中间几位为散列函数的值。因为一个数平方后的中间几位和原数的每一位都相关,因此,使用随机分布的关键字得到的记录的存储位置也是随机的。适用于关键字的每位取值都不够均匀或均小于散列地址所需的位数。
+ 折叠法:将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为散列函数的值, 称为折叠法。例如, 假设关键字为某人身份证号码430104681015355, 则可以用4位为一组进行叠加, 即有5355+ 8101+ 1046+ 430= 14932, 舍去高位, 则有H(430104681015355)= 4932。
@@ -252,6 +252,6 @@ $H_i=RH_i(Key)\,i=1,2,\cdots,k$。
若散列函数设计得足够好,散列查找时间复杂度可以达到$O(1)$,即不存在冲突。
**装填因子 ** =表中记录数/ 散列表长度。装填因子代表一个散列表中的满余情况,越大则查找效率越低。
**装填因子 ** =表中记录数÷ 散列表长度。装填因子代表一个散列表中的满余情况,越大则查找效率越低。
若只给出了装填因子$\alpha$,则此时平均查找长度为:$ASL=\dfrac{1}{2}(1+\dfrac{1}{1-\alpha})$。