几个查找算法
折半查找
也叫二分查找
, 前提是顺序表 有序
key
与中间元素比较, 若相等, 查找成功, 返回元素位置; 若不等, 根据大小查找左半部分或右半部分 // 折半查找
public int binarySearch(int A[], int key) {
int low = 0;
int high = A.length - 1;
while (low <= high) {
int mid = (low + high) / 2; // 中间位置
if (key == A[mid]) { // 查找成功则返回所在位置
return mid;
} else if (key < A[mid]) { // 查找前半部分
high = mid - 1;
} else { // 查找右半部分
low = mid + 1;
}
}
return -1; // 查找失败
}
O(logn)
(log
表示以2为底的对数)[m/2]
意思为向上取整B树
又称多路平衡查找树
或多路平衡查找树
, 但一般把二叉平衡排序树
成为B树
, 把
排序树
也叫查找树
, 以二叉平衡树为例说明, 左子树结点都小于根, 右子树结点都大于根m
阶的B树
最多有m
棵子树, 如下图为3阶B树示例:m
阶的B树
的每个结点最多包含m-1
个关键字, m
棵子树. 结点的结构类似于下图:K1<K2<...<Kn
, P(i-1)
子树的关键字都小于Ki
, P(i)
子树的关键字都大于Ki
[m/2]
棵子树, [m/2] -1
个关键字(插入时分裂是从中间分裂的)B树
一般是保存在磁盘上的, B树
的查找跟二叉树的查找很像, 只不过每个结点变成了一个多关键字的有序表.
B树
的查找分个基本操作:
B树
中找结点, 把找到的结点
从磁盘读入内存结点
内找关键字, 这个操作在内存中进行, 相当于在一个有序表中查找关键字K, 可以使用顺序查找或二分查找若在结点上找到与关键字K则查找成功, 否则按照对应的指针去下一个结点中找, 当指针为空还没找到, 则查找失败
B树
的插入操作比二叉查找树要复杂, 并不能简单的找到终端结点然后添加到进去, 因为有可能插入结点后就不再满足B树
的定义要求了.
把关键字key
插入到B树
的过程如下:
m-1
, 所以若插入后关键字个数小于m
则可以直接插入, 若等于m
则必须对结点进行分裂
.分裂
的方法:
key
后的原结点从中间位置([m/2]
)分成两部分[m/2]
)的关键字插入到原结点的父结点中.B树
的高度增1.B树
的删除与插入类似, 但更复杂一些, 要涉及结点的合并
.
当要删除的关键字k
不在终端结点时:
k的左边子树
(k
与k-1
之间的子树)关键字个数n有n >= [m/2] -1
, 则找出k
的前驱值k'
(k的左边子树
中最大的那个), 用k'
取代k
, 再递归地删除k'
. 最终会传递下去转变成在终端结点的情况.k的右边子树
(k
与k+1
之间的子树)关键字个数n有n >= [m/2] -1
, 则找出k
的后继值k'
(k的右边子树
中最小的那个), 用k'
取代k
, 再递归地删除k'
. 最终会传递下去转变成在终端结点的情况.[m/2] -1
, 则把左右两个子树合并成一个子树(这样合并后仍不会超过m-1
), 直接删除k
即可当要删除的关键字k
在终端结点时:
n > [m/2] -1
, 则直接删除关键字k
, 写入磁盘n = [m/2] -1
, 但相邻的右兄弟结点关键字n > [m/2] -1
, 此时为兄弟够借的情况; 这时调整左兄弟, 右兄弟, 父结点, 具体做法是右兄弟的最小值调整到到父结点(左右兄弟中间那个值), 父结点那个关键字调整到到左兄弟n = [m/2] -1
, 但相邻的右兄弟结点关键字n = [m/2] -1
, 此时为兄弟不够借的情况; 这时删除关键字k
后, 把左兄弟, 父结点, 右兄弟的关键字进行合并B+树
广泛应用于数据库存储引擎
一棵m
阶的B+树
需满足下列条件:
m
棵子树[m/2]
棵子树([]
表示向上取整)B+树
的例子:B+树
中一个结点有n
个关键字就有n
棵子树, 即每个关键字对应一颗子树; B树
中有n
个关键字的节点含有n+1
棵子树B+树
中非根结点关键字的个数n
范围是[m/2] <= n <= m
; B树
中为[m/2]-1 <= n <= m
B+树
中的非叶子节点仅起到索引的作用, 不包含关键字对应记录的存储地址; B树
中是有存储数据的B+树
中叶子节点包含全部关键字; B树
中叶子结点包含的关键字和其他结点是不重复的, 所有结点加起来才是全部关键字