mirror of
https://github.com/Didnelpsun/CS408.git
synced 2026-02-10 22:25:48 +08:00
更新查找
This commit is contained in:
34
Code/Code/head/search.h
Normal file
34
Code/Code/head/search.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#include "head.h"
|
||||
|
||||
typedef int elem_type
|
||||
|
||||
// 线性表
|
||||
typedef struct {
|
||||
elem_type *elem;
|
||||
int length;
|
||||
} LinearTable;
|
||||
|
||||
// 顺序查找
|
||||
int SequenceSearch(LinearTable table, elem_type key) {
|
||||
for (int i = 0; i < table.length; i++) {
|
||||
if (table.elem[i] == key)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 折半查找
|
||||
int BinarySearch(LinearTable table, elem_type key) {
|
||||
int low = 0, high = table.length - 1, mid;
|
||||
while (low <= high) {
|
||||
mid = (low + high) / 2;
|
||||
if (table.elem[mid] == key)
|
||||
return mid;
|
||||
else if (table.elem[mid] > key)
|
||||
high = mid - 1;
|
||||
else
|
||||
low = mid + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "../head/thread_tree.h"
|
||||
#include "../head/tree.h"
|
||||
#include "../head/graph.h"
|
||||
#include "../head/search.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -318,7 +318,7 @@
|
||||
|
||||
#### Dijkstra算法
|
||||
|
||||
即迪杰斯特拉算法。
|
||||
即迪杰斯特拉算法。用于计算单源最短路径(要计算从源到其他所有各顶点的最短路径长度)。
|
||||
|
||||
1. 从$v_0$开始,初始化三个数组:标记各顶点是否已找到最短路径$final$;最短路径长度$dist$;最短路径上的前驱$path$。从$v_0$开始,所以将$final[0]=true$,$dist[0]=0$,$path[0]=-1$,然后将$v_0$直连的点的$dist$初始化为直连路径长度,对应的$path=0$,但是不要将对应的$final=true$,因为还没有确定对应的直连路径就是最短路径。其他顶点的$dist=\infty$。
|
||||
2. 遍历所有结点,找到还没确定最短路径,且最短路径长度值最小的的一个顶点,这就确定了下一个最短路径的结点,令其各顶点是否已找到最短路径的值为$true$。
|
||||
@@ -403,9 +403,9 @@ $AOV$网:用$DAG$图表示一个工程,顶点表示活动,有向边$<v_i,v
|
||||
+ 只有一个出度为$0$的顶点,称为结束顶点(汇点),表示整个工程的结束。
|
||||
|
||||
+ 从源点到汇点的有向路径可能有多条,所有路径中,具有最大路径长度的路径称为关键路径(即决定完成整个工程所需的最小时间),而关键路径上的活动称为关键活动。
|
||||
+ 事件的最早发生时间:决定了所有从该事件开始的活动能够开工的最早时间。
|
||||
+ 事件的最早发生时间:决定了所有从该事件开始的活动能够开工的最早时间。一个事件的最早发生时间与以该事件为始的弧的活动的最早开始时间相同。
|
||||
+ 活动的最早开始时间:指该活动弧的起点所表示的事件最早发生时间。
|
||||
+ 事件的最迟发生时间:在不推迟整个工程完成的前提下,该事件最迟必须发生的时间。
|
||||
+ 事件的最迟发生时间:在不推迟整个工程完成的前提下,该事件最迟必须发生的时间。一个事件的最迟发生时间等于$\min${以该事件为尾的弧的活动的最迟开始时间,最迟结束时间与该活动的持续时间的差}。
|
||||
+ 活动的最迟开始时间:指该活动弧的终点所表示的事件的最迟发生时间与该活动所需时间之差。
|
||||
+ 活动的时间余量:在不增加完成整个工程所需总时间的情况下,活动可以拖延的时间。
|
||||
|
||||
|
||||
49
Data-Structrue/9-search-ex.md
Normal file
49
Data-Structrue/9-search-ex.md
Normal file
File diff suppressed because one or more lines are too long
@@ -5,10 +5,10 @@
|
||||
+ 查找:在数据集合中寻找满足某种条件的数据元素的过程。
|
||||
+ 查找表(查找结构):用于查找的数据集合,由同一类型的数据元素或记录组成。
|
||||
+ 关键字:数据元素中唯一标识该元素的某个数据项的值,使用基于关键字的查找,查找结果应该唯一。
|
||||
+ 静态查找表:只查找符合条件的数据元素。
|
||||
+ 动态查找表:出来要查找,还要进行删除或插入,除了查找速度还要考虑插入删除操作是否方便。
|
||||
+ 静态查找表:只查找符合条件的数据元素。(顺序查找、折半查找、散列查找)
|
||||
+ 动态查找表:出来要查找,还要进行删除或插入,除了查找速度还要考虑插入删除操作是否方便。(二叉排序树查找、散列查找)
|
||||
+ 查找长度:查找运算中,需要对比关键字的次数。
|
||||
+ 平均查找长度ASL:所有查找过程中进行关键字比较次数的平均值。$ASL=\sum_{i=1}^nP_iC_i$。其中$P_i$表示查找第i个元素的概率,$C_i$表示查找第i个元素的查找长度。
|
||||
+ 平均查找长度$ASL$:所有查找过程中进行关键字比较次数的平均值。$ASL=\sum_{i=1}^nP_iC_i$。其中$P_i$表示查找第$i$个元素的概率,$C_i$表示查找第$i$个元素的查找长度。
|
||||
|
||||
## 线性表查找
|
||||
|
||||
@@ -16,20 +16,26 @@
|
||||
|
||||
又称为线性查找,常用于线性表,从头到尾逐个查找。
|
||||
|
||||
ASL查找成功为$\dfrac{1+2+3+\cdots+n}{n}=\dfrac{n+1}{2}$,ASL查找失败为$n+1$,时间复杂度为$O(n)$。
|
||||
#### 一般查找
|
||||
|
||||
在算法实现时一般将线性表的$0$号索引的元素值设为查找的值,从表最后面开始向前查找,当没有找到时就直接从$0$返回。这个数据称为哨兵,可以避免不必要的判断线性表长是否越界语句从而提高程序效率。
|
||||
|
||||
$ASL$查找成功为$\dfrac{1+2+3+\cdots+n}{n}=\dfrac{n+1}{2}$,$ASL$查找失败为$n+1$,时间复杂度为$O(n)$。
|
||||
|
||||
#### 顺序表
|
||||
|
||||
可以让数据集变为有序的,这样对比数据大小也可以知道是否还需要遍历从而减少查找时间。这样顺序结构从逻辑上就变成了一个二叉树结构,左子树代表小于,右子树代表大于,所有数据结点挂在右子树上。
|
||||
可以让数据集变为有序的,这样对比数据大小也可以知道是否还需要遍历从而减少查找时间。这样顺序结构从逻辑上就变成了一个二叉树结构(一般是顺序的),左子树代表小于(失败结点),右子树代表大于(需要继续向右查找),所有数据结点挂在右子树上。
|
||||
|
||||
查找情况还要比普通乱序查找加上一个大于最大值的情况。
|
||||
|
||||
ASL查找失败为$\dfrac{1+2+3+\cdots+n+n}{n+1}=\dfrac{n}{2}+\dfrac{n}{n+1}$。成功结点的查找长度等于自身所在层数,失败结点的查找长度等于其父结点所在层数。
|
||||
$ASL$查找失败为$\dfrac{1+2+3+\cdots+n+n}{n+1}=\dfrac{n}{2}+\dfrac{n}{n+1}$。成功结点的查找长度等于自身所在层数,失败结点的查找长度等于其父结点所在层数。
|
||||
|
||||
#### 查找概率不等
|
||||
|
||||
当数据元素查找概率不等时,可以将查找概率更大的元素放在靠前的位置,以减少大概率元素被遍历的时间。
|
||||
|
||||
$ASL$查找成功为$\sum\limits_{i=1}^nP_i(n-i+1)$,$P_i$为第$i$个元素出现概率。
|
||||
|
||||
但是此时数据是乱序的,所以查找失败的时间复杂度与没有优化的是一样的。
|
||||
|
||||
### 折半查找
|
||||
@@ -38,29 +44,30 @@ ASL查找失败为$\dfrac{1+2+3+\cdots+n+n}{n+1}=\dfrac{n}{2}+\dfrac{n}{n+1}$。
|
||||
|
||||
#### 折半查找的结构
|
||||
|
||||
定义三个指针,low指向查找范围的最小值,high指向查找范围的最大值,mid指向查找范围的中间值,$mid=\lfloor(low+high)\div2\rfloor$。(也可以向上取整,过程会有所不同)
|
||||
定义三个指针,$low$指向查找范围的最小值,$high$指向查找范围的最大值,$mid$指向查找范围的中间值,$mid=\lfloor(low+high)\div2\rfloor$。(也可以向上取整,过程会有所不同)
|
||||
|
||||
#### 折半查找的过程
|
||||
|
||||
查找时,首先计算出mid判断是否相等,若查找值小于mid的值,则将high赋值为mid的值,若查找值大于mid,则将low赋值为mid的值,重新计算mid。这样就可以不断二分区间来查找,从而加快迭代。当查找最后low>high则查找失败。
|
||||
查找时,首先计算出$mid$判断是否相等,若查找值小于$mid$的值,则将$high$赋值为$mid-1$的值,若查找值大于$mid$,则将$low$赋值为$mid+1$的值,重新计算$mid$。这样就可以不断二分区间来查找,从而加快迭代。当查找最后$low>high$则查找失败。
|
||||
|
||||
ASL查找成功为$\dfrac{1+2+3+\cdots+n}{n}=\dfrac{n+1}{2}$,ASL查找失败为$n+1$,时间复杂度为$O(n)$。
|
||||
$ASL$查找成功为$\dfrac{1+2+3+\cdots+n}{n}=\dfrac{n+1}{2}$,$ASL$查找失败为$n+1$,时间复杂度为$O(n)$。
|
||||
|
||||
#### 折半查找判定树
|
||||
|
||||
若当前low和high有奇数个元素,则mid分割后左右两部分元素个数相等。
|
||||
折半查找的过程可用二叉树来描述,称为判定树。树中每个圆形结点表示一个记录,结点中的值为该记录的关键字值;树中最下面的叶结点都是方形的,它表示查找不成功的情况。从判定树可以看出,查找成功时的查找长度为从根结点到目的结点的路径上的结点数,而查找不成功时的查找长度为从根结点到对应失败结点的父结点的路径上的结点数。
|
||||
|
||||
若当前low和high有奇数个元素,则mid分割后左部分元素个数小于右部分一个。
|
||||
+ 若当前$low$和$high$有奇数个元素,则$mid$分割后左右两部分元素个数相等。
|
||||
+ 若当前$low$和$high$有奇数个元素,则$mid$分割后左部分元素个数小于右部分一个。
|
||||
+ 折半查找判定树一定是一个平衡二叉树。只有最下面一层不满,元素个数为$n$时树高与完全二叉树相等$h=\lceil\log_2(n+1)\rceil$。
|
||||
+ 根据折半查找判定树可以计算对应的$ASL$:查找成功的$ASL$=($\sum\limits_{i=1}^n$第$i$层的成功结点数$\times i$)$\div$成功结点总数,查找失败的$ASL$=($\sum\limits_{i=1}^n$第$i$层的失败结点数$\times i$)$\div$失败结点总数。
|
||||
+ 折半查找判定树也是一个二叉排序树,失败结点$=n+1$(成功结点的空链域节点数)。
|
||||
+ 折半查找判定树的中序序列应该是一个有序序列。
|
||||
|
||||
折半查找判定树一定是一个平衡二叉树。只有最下面一层不满,元素个数为n时树高与完全二叉树相等$h=\lceil\log_2(n+1)\rceil$。
|
||||
|
||||
且折半查找判定树也是一个二叉排序树,失败结点=n+1(成功结点的空链域节点数)。
|
||||
|
||||
ASL查找成功查找失败都一定小于折半查找树的树高,时间复杂度为$O(\log_2n)$。
|
||||
$ASL$查找成功查找失败都一定小于折半查找树的树高,时间复杂度为$O(\log_2n)$。
|
||||
|
||||
### 分块查找
|
||||
|
||||
分块查找又称为索引顺序查找,需要对数据进行一定的排序,不一定全部是顺序的,但是要求在一个区间内是满足一定条件的,即块内无序,块间有序。其中分割的块数和每块里的数据个数都是不定的。
|
||||
分块查找又称为索引顺序查找,需要对数据进行一定的排序,不一定全部是顺序的,但是要求在一个区间内是满足一定条件的,即块内无序,块间有序。将查找表分割为若干子块,其中分割的块数和每块里的数据个数都是不定的。
|
||||
|
||||
#### 分块查找的结构
|
||||
|
||||
@@ -76,11 +83,11 @@ ASL查找成功查找失败都一定小于折半查找树的树高,时间复
|
||||
|
||||
在查找时先根据关键字遍历索引表,然后找到索引表的分块(可以顺序也可以折半),再到存储数据的顺序表的索引区间中查找。
|
||||
|
||||
若适用折半查找查找索引表的分块,索引表中若不存在目标关键字,则折半查找索引表最终会停在low>high,要在low所指向分块中查找。
|
||||
若适用折半查找查找索引表的分块,索引表中若不存在目标关键字,则折半查找索引表最终会停在$low>high$,要在$low$所指向分块中查找。
|
||||
|
||||
#### 分块查找的效率
|
||||
|
||||
ASL查找成功失败的情况都十分复杂,所以一般不会考。
|
||||
$ASL$查找成功失败的情况都十分复杂,所以一般不会考。
|
||||
|
||||
假设长度为$n$的查找表被均匀分为$b$块,每块$s$个元素,假设索引查找和块内查找的平均查找长度ASL分别为$L_I$和$L_S$,则分块查找的平均查找长度为$ASL=L_I+L_S$。
|
||||
|
||||
@@ -94,35 +101,51 @@ ASL查找成功失败的情况都十分复杂,所以一般不会考。
|
||||
|
||||
#### B树的定义
|
||||
|
||||
为了保证m叉查找树中每个结点都能被有效利用,避免大量结点浪费导致树高过大,所以规定m叉查找树中,除了根结点以外,任何结点至少有$\lceil\dfrac{m}{2}\rceil$个分叉,即至少包含$\lceil\dfrac{m}{2}\rceil-1$个结点。
|
||||
为了保证$m$叉查找树中每个结点都能被有效利用,避免大量结点浪费导致树高过大,所以规定$m$叉查找树中,除了根结点以外,任何结点至少有$\lceil\dfrac{m}{2}\rceil$个分叉,即至少包含$\lceil\dfrac{m}{2}\rceil-1$个结点。
|
||||
|
||||
为了保证m叉查找树是一棵平衡树,避免树偏重导致树高过大,所以规定m叉查找树中任何一个结点,其所有子树的高度都要相同。
|
||||
为了保证$m$叉查找树是一棵平衡树,避免树偏重导致树高过大,所以规定$m$叉查找树中任何一个结点,其所有子树的高度都要相同。
|
||||
|
||||
而能保证这两点的查找树,就是一棵B树,多少叉,就是一棵多少阶的B树。
|
||||
而能保证这两点的查找树,就是一棵$B$树,即多路平衡查找树,多少叉,就是一棵多少阶的$B$树。
|
||||
|
||||
B树即多路平衡查找树,所有结点的孩子个数的最大值就是B树的阶,一般用m表示。
|
||||
非叶结点定义:$\{n,P_0,K_1,P_1,\cdots,K_n,P_n\}$。其中$K_i$为结点关键字,$K_1<K_2<\cdots<K_n$,$P_i$为指向子树根节点的指针。$P_{i-1}$所指子树所有结点的关键字均小于$K_i$,$P_i$所指子树的关键字均大于$K_i$。
|
||||
|
||||
#### B树的性质
|
||||
|
||||
+ 树的每个结点至多包含m棵子树,至多包含m-1个关键字。
|
||||
+ B树最底端的失败的不存在的结点就是常说的叶子结点,而最底端的存在数据的结点就是终端结点。(一般的树的叶子结点和终端结点都是指最底端的有数据的结点)
|
||||
+ 树的每个结点至多包含$m$棵子树,至多包含$m-1$个关键字。
|
||||
+ 若根结点不是终端结点,则至少有两颗子树,任意结点的每棵子树都是绝对平衡的。
|
||||
+ 除根结点以外的所有非叶结点至少有$\lceil\dfrac{m}{2}\rceil$棵子树,即至少包含$\lceil\dfrac{m}{2}\rceil-1$个结点。
|
||||
+ 每个结点中的关键字是有序的。子树$0$<子树$1$<子树$2$<……。
|
||||
+ 所有叶结点都出现在同一个层次上且不带信息。
|
||||
+ 每个结点中的关键字是有序的。子树0 < 关键字1 < 子树2 < ...。
|
||||
+ $B$树最底端的失败的不存在的结点就是常说的叶子结点,而最底端的存在数据的结点就是终端结点。(一般的树的叶子结点和终端结点都是指最底端的有数据的结点)
|
||||
+ 携带数据的是内部结点,最底部的叶子结点也称为外部结点。
|
||||
|
||||
计算B树高度大部分不包括叶子结点。若含有n个关键字的m阶B树。
|
||||
#### B树的高度
|
||||
|
||||
$B$树中的大部分操作所需的磁盘存取次数与$B$树的高度成正比。
|
||||
|
||||
计算$B$树高度大部分不包括叶子结点。若含有$n$个关键字的$m$阶$B$树。
|
||||
|
||||
+ 最小高度:让每个结点尽可能满,有$m-1$个关键字,$m$个分叉,则一共有$(m-1)(m^0+m^1+m^2+\cdots+m^{h-1})$个结点,其中$n$小于等于这个值,从而求出$h\geqslant\log_m(n+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$。
|
||||
+ 让各层分叉尽可能少,即根结点只有两个分叉,其他结点只有$\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\frac{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\frac{m}{2}\rceil}\dfrac{n+1}{2}+1$。
|
||||
|
||||
#### B树的查找
|
||||
|
||||
$B$树的查找包含两个基本操作:
|
||||
|
||||
1. 在$B$树中找结点。
|
||||
2. 在结点内找关键字。
|
||||
|
||||
由于$B$树常存储在磁盘上,因此前一个查找操作是在磁盘上进行的,而后一个查找操作是在内存中进行的,即在找到目标结点后,先将结点信息读入内存,然后在结点内采用顺序查找法或折半查找法。
|
||||
|
||||
在$B$树上查找到某个结点后,先在有序表中进行查找,若找到则查找成功,否则按照对应的指针信息到所指的子树中去查找,则说明树中没有对应的关键字,查找失败。
|
||||
|
||||
#### B树的插入
|
||||
|
||||
新元素插入一定是插入到最底层的终端结点,使用B树的查找来确定插入位置。
|
||||
新元素插入一定是插入到最底层的终端结点,使用$B$树的查找来确定插入位置。
|
||||
|
||||
若导致原结点关键字数量超过上限溢出,就从中间位置$\lceil\dfrac{m}{2}\rceil$分开,将左部分包含的关键字放在原来结点,右部分包含的关键字放在一个新结点,并插入到原结点的父结点的后一个位置上,而在原结点的父结点连接后的结点后移一个连接让位给分割出来的右半部分结点,中间的一个结点$\lceil\dfrac{m}{2}\rceil$插入到原结点的父结点上,并考虑在父结点的顺序。
|
||||
若导致原结点关键字数量超过上限溢出,就从中间位置$\lceil\dfrac{m}{2}\rceil$分开,将左部分包含的关键字放在原来结点,右部分包含的关键字放在一个新结点,并插入到原结点的父结点的后一个位置上,而在原结点的父结点连接后的结点后移一个连接让位给分割出来的右半部分结点,中间的一个结点$\lceil\dfrac{m}{2}\rceil$插入到原结点的父结点上,并考虑在父结点的顺序对指针进行调整保证顺序。
|
||||
|
||||
若父结点插入时也溢出了,则同理在父结点的中间进行分割,左半部分在原来父结点;右半部分新建一个父结点,并把中间结点右边开始的所有连接移动到新父结点上;中间的结点上移到祖父结点,如果没有就新建,然后建立两个指针分别指向原父结点和新父结点。
|
||||
|
||||
@@ -130,51 +153,50 @@ B树即多路平衡查找树,所有结点的孩子个数的最大值就是B树
|
||||
|
||||
+ 若被删除关键字在终端结点,且结点关键字个数不低于下限,则直接删除该关键字,并移动后面的关键字。
|
||||
+ 若被删除关键字在非终端结点,则用直接前驱或直接后继来替代被删除关键字,然后后面的元素直接前移。
|
||||
+ 直接前驱:当前关键字左侧指针所指子树最右下的元素。
|
||||
+ 直接后继:当前关键字右侧指针所指子树最左下的元素。
|
||||
+ 直接前驱:当前关键字左侧指针所指子树遍历到最右下的元素。
|
||||
+ 直接后继:当前关键字右侧指针所指子树遍历到最左下的元素。
|
||||
+ 若被删除关键字在终端结点,但是结点关键字个数删除后低于下限:
|
||||
+ 右兄弟够借:若原结点右兄弟结点里的关键字在删除一个后高于下限,则可以用结点的后继以及后继的后继来顶替:
|
||||
1. 将原结点在父结点的连接的前一个关键字下移到原结点并放在最后面。
|
||||
2. 原结点父结点里的关键字全部前移一位。
|
||||
3. 将原结点右兄弟结点的第一个关键字上移插入到原结点父结点的关键字的最后面。
|
||||
4. 原结点右兄弟结点里的关键字全部前移一位。
|
||||
1. 将原结点在父结点的连接的后一个关键字下移到原结点并放在最后面。
|
||||
2. 将原结点右兄弟结点的第一个关键字上移插入到下移的元素的空位。
|
||||
3. 原结点右兄弟结点里的关键字全部前移一位。
|
||||
+ 左兄弟够借:若原结点里右兄弟的关键字在删除一个后低于下限,但是左兄弟的结点足够,则可以用结点的前驱以及前驱的前驱来顶替:
|
||||
1. 将原结点在父结点的连接的前一个关键字下移到原结点并放在最前面。
|
||||
2. 原结点父结点里的关键字全部前移一位。
|
||||
3. 将原结点左兄弟结点的最后一个关键字上移插入到原结点父结点的关键字的最前面。
|
||||
4. 原结点兄左弟结点里的关键字全部前移一位。
|
||||
+ 左右兄弟都不够借:若 左右兄弟结点的关键字个数均等于下限值,则将关键字删除后与左或右兄弟结点以及父结点中的关键字进行合并:
|
||||
1. 将原结点的父结点关键字插入到原结点关键字后面。
|
||||
1. 将原结点在父结点的连接的前一个关键字下移到原结点并放在最前面,其余元素后移。
|
||||
2. 将原结点左兄弟结点的最后一个关键字上移插入到原结点父结点的连接的前面。
|
||||
3. 原结点左兄弟结点里的关键字全部前移一位。
|
||||
+ 左右兄弟都不够借:若左右兄弟结点的关键字个数均等于下限值,则将关键字删除后与左或右兄弟结点以及父结点中的关键字进行合并:
|
||||
1. 将原结点的父结点连接后的关键字插入到原结点关键字最后面。
|
||||
2. 将原结点的左或右兄弟结点的关键字合并到原结点(前插或后插),并将连接也转移到原结点上。
|
||||
3. 若父结点的关键字个数又不满于下限,则父结点同样要于与它的兄弟父结点进行合并,并不断重复这个过程。
|
||||
4. 若父结点为空则删除父结点。
|
||||
|
||||
### B+树
|
||||
|
||||
B+树考的并不是很深。
|
||||
$B+$树考的并不是很深。用于数据库。
|
||||
|
||||
与分块查找类似,是对B树的一种变型。
|
||||
与分块查找的思想类似,是对$B$树的一种变型。
|
||||
|
||||
#### B+树的定义
|
||||
|
||||
一个m阶的B+树需要满足以下条件:
|
||||
一个$m$阶的$B+$树需要满足以下条件:
|
||||
|
||||
1. 每个分支结点最多有m棵子树或孩子结点。
|
||||
2. 为了保持绝对平衡,非叶根结点至少有两棵子树,其他每个分支结点至少有$\lceil\dfrac{m}{2}\rceil$棵子树。(不同于B树,B+树又重新将最下面的保存的数据定义为叶子结点)
|
||||
3. 结点的子树个数与关键字个数相等。(B树结点子为树个数与关键字个数加1)
|
||||
4. 所有叶结点包含所有关键字以及指向记录的指针,叶结点中将关键字按大小排序,并且相邻叶子结点按大小顺序相互连接起来。所以B+树支持顺序查找。
|
||||
1. 每个分支结点最多有$m$棵子树或孩子结点。
|
||||
2. 为了保持绝对平衡,非叶根结点至少有两棵子树,其他每个分支结点至少有$\lceil\dfrac{m}{2}\rceil$棵子树。(不同于$B$树,$B+$树又重新将最下面的保存的数据定义为叶子结点)
|
||||
3. 结点的子树个数与关键字个数相等。($B$树结点子为树个数与关键字个数加$1$)
|
||||
4. 所有叶结点包含所有关键字以及指向记录的指针,叶结点中将关键字按大小排序,并且相邻叶子结点按大小顺序相互连接起来。所以$B+$树支持顺序查找。
|
||||
5. 所有分支结点中仅包含其各子结点中关键字的最大值以及指向其子结点的指针(即分支结点只是索引)。
|
||||
|
||||
#### B+树的查找
|
||||
|
||||
无论查找成功与否,B+树的查找一定会走到最下面一层结点,否则无法确认。而B树查找可以停留在任何一层。
|
||||
无论查找成功与否,$B+$树的查找一定会走到最下面一层结点,因为对应的信息指针都在最下面的结点。而$B$树查找可以停留在任何一层。
|
||||
|
||||
B+树可以遍历查找,即从根结点出发,对比每个结点的关键字值,若目标值小于当前关键字值且大于前一个关键字值,则从当前关键字的指针向下查找。
|
||||
$B+$树可以遍历查找,即从根结点出发,对比每个结点的关键字值,若目标值小于当前关键字值且大于前一个关键字值,则从当前关键字的指针向下查找。
|
||||
|
||||
B+树可以顺序查找,在叶子结点的块之间定义指向后面叶子结点块的指针,从而能顺序查找。
|
||||
$B+$树可以顺序查找,在叶子结点的块之间定义指向后面叶子结点块的指针,从而能顺序查找。
|
||||
|
||||
#### B+树与B树的区别
|
||||
|
||||
对于m阶B+树与B树:
|
||||
对于$m$阶$B+$树与$B$树:
|
||||
|
||||
|B+树|B树
|
||||
:--:|:--:|:--:
|
||||
|
||||
Reference in New Issue
Block a user