之前在Linux内核开发大会上听到B+树,当时不明白B+树是个什么东西,百科了一下更是看的一头雾水,翻起数据结构的书一点点看吧(数据结构要学好啊!!!)。
本文只讲求了解、明白二叉搜索树等之的概念,常见操作如插入、删除、查找,不涉及具体代码的编写,因为C、Cplus、java各有在二叉树上不同的风格,大家在项目代码见到了知道这是二叉搜索树或是B-树,知道是查找操作还是删除操作就哦了,一般我们不会去改动这部分的源码,知道如何引用人家的源码就够了,学会站在巨人的肩上解决问题!
二叉搜索树:也叫二叉排序树。二叉搜索树是一颗二叉树(可以为空),其左子树节点上的关键值均小于父节点的关键值,其右子树节点上的关键值均大于父节点的关键值。其子树也是二叉搜索树(递归定义)。由二叉搜索树的定义我们可以得到一些性质:若以中序遍历二叉搜索树可得到一个以关键值递增排序的有序序列。关于二叉搜索树的操作,这里只介绍思想,不贴代码了。二叉搜索树的搜索有递归方法和非递归方法,非递归方法就是在while循环里进行指针的传递,要查找的元素x如果小于当前节点关键值,则查找其左子树,如果大于当前节点关键值,则查找其右子树,等于当前节点关键值,则返回指向当前节点的指针。虽然非递归的实现要快一点,但是递归的实现更讲究、更精彩,所以实际项目中大多使用递归。二叉搜索树的插入,首先应该查找要插入元素x的应该插入的位置,同时记录该位置的父节点,然后生成新节点将这元素x存放在最后记录的那个节点的左子树或右子树。利用二叉搜索树的插入操作可以构建一支二叉搜索树。二叉搜索树的删除相对复杂点,要考虑的问题有点多,如果要删除的元素x是叶子节点,则直接删除;若x只有一个子树,则其父节点调整一下指针,使指向该节点的子节点,绕过该节点就实现了删除;若x有两个子树,一般的删除策略是用其右子树中最小的数据代替该节点并递归的删除那个最小节点,因为最小节点不可能有左子树,所以第二次删除就转换成x只有一个子树的情况。
二叉平衡树:又称AVL树。是一种二叉排序树,其中每个节点的左子树和右子树的高度差的绝对值不超过1。其根的左子树和右子树也是二叉平衡树(递归定义),节点左子树与右子树的高度差称为平衡因子BF(Balance Factor)。AVL树不再深入介绍,因为关于它的旋转转化比较复杂,有兴趣的可以自行查阅。
我们都知道计算机上的存储空间有内存和外存,当我们的数据集合比较小时存放在内存中,这时的搜索操作称为内搜索,内搜索一般用二叉平衡树表示集合。如果数据文件比较大,内存不下只能存在外存,这时的数据搜索称为外搜索,外搜索一般用B-树表示集合。一般从磁盘这类外存的存取时间是1ms~10ms,而典型内存的存取时间是10ns~100ns比外存快了100W倍!所以设法减少磁盘存取操作是外搜索算法应该主要考虑的问题。
介绍B-树之前得先介绍m叉搜索树。m叉搜索树可以是一棵空m叉搜索树,或者是一棵满足下列特性的树。
⑴ 根结点最多有m棵子树,并具有如下结构: n,P0,(K1,P1),(K2,P2),…,(Kn,Pn), 其中,Pi是指向子树的指针,0≤i≤n< m, Ki是关键值,1≤ i≤ n<m。
⑵ Ki<Ki+1 , 1≤i<n
⑶ 子树Pi上的所有关键字值都大于Ki,小于Ki+1,0<i<n。
⑷ 子树P0上的所有关键字值都小于K1,子树Pn上的所有关键字值都大于Kn。
⑸ 子树Pi(0≤ i≤ n)也是m叉搜索树。
m叉搜索树的每个节点中最多存放m-1个元素和m个指针,每个结点中元素按关键值递增排列,一个元素的关键值大于它的左子树上所有结点中元素的关键值,小于右子树上所有结点中元素的关键值。失败节点即指针值为NULL。
B-树就是多叉搜索树,m叉搜索树称为m阶B-树。且满足以下特点:
⑴根结点至少有两个孩子。
⑵除根结点和失败结点外的所有结点至少有m/2个孩子,最多有m个孩子。
⑶所有失败结点均在同一层上。
从定义中可以得到,一棵4阶B-树中(1)一个结点最多有4个孩子。(2)除根结点和失败结点外每个结点最少有 4/2 =2个孩子, 根结点最少有2个孩子(3)所有失败结点均在同一层上。
B-树的搜索算法与m叉搜索树的搜索算法相同。但B-树搜索需执行的磁盘访问次数最多是 1+logm/2 ((N+1)/2) N是元素个数,m是阶数。 B-树的每个结点可以看成一个有序表,在一个B-树结点中搜索时可以看成在内存中的搜索,因此可以采用顺序搜索和二分搜索等内搜索算法进行。