B树的思路以及go语言实现【算法】
一、定义
B树B-tree,B-树其实就是B树,英文名balanced tree。一棵m阶B树(balanced tree of order m)是一棵平衡的m路搜索树。它或者是空树,或者是满足下列性质的树:
1、根结点至少有两个子女;
2、每个非根节点所包含的关键字个数 j 满足:┌m/2┐ - 1 <= j <= m - 1;
3、除根结点以外的所有结点(不包括叶子结点)的度数正好是关键字总数加1,故内部子树个数 k 满足:┌m/2┐ <= k <= m ;
4、所有的叶子结点都位于同一层。
5、B树是搜索树(有序)
二、思路实现
B树设计初衷就是为了查找,所以查找是最简单的,相反插入、删除反而异常繁琐,每次操作都会多次使用查找。这里我这要分析B树中如何插入及删除,。
插入操作,一般搜索树而言,插入就是找到相应的位置,直接加入节点,B树为了数据能够快速被查找,在插入的时候不仅要插入到相应的位置,还需要根据情况来调整树的高度以及宽度,尽可能使树高度下降。
插入分为以下几种:
1、若插入的节点中含有的关键词小于m-1,则正常添加关键词到节点即可
2、若插入的节点中含有关键词等于m-1(这里不存在大于m-1,因为一旦达到m就会分裂),则需要向上分裂(这个是需要递归到根节点)
//r为根节点指针,key为插入关键词,value是插入的数据
func InsertTreeNode(r *node, key int16, value int16) int16 {
if r.indexesNum == 0 { // 根节点为空
fmt.Println("root is empty node", r)
r.indexes = make([]int16, M+1, M+1)
r.vals = make([]int16, M+1, M+1)
r.children = make([]*node, M+1, M+1)
var i int16
for i = 0; i <= M; i++ {
r.indexes[0] = 0
r.vals[i] = 0
r.children[i] = nil
}
r.indexesNum++
r.indexes[1] = key
r.vals[1] = value
} else {
// Find out if this node exists
res, pos, state := FindOfNode(r, key)//res是查找到的节点,pos找到插入的位置
if state == TRUE {// 每次查找都需要判断是否存在数据
fmt.Println("This n node is exist!")
return ERROR
}
if state == FALSE {// 不存在关键词,表示可以插入
res.indexesNum++
var i int16
for i = res.indexesNum; i > pos; i-- {
res.indexes[i] = res.indexes[i-1]
res.children[i] = res.children[i-1]
res.vals[i] = res.vals[i-1]
}
res.indexes[pos] = key
res.vals[pos] = value
res.children[pos] = nil
if res.indexesNum == M {//这里就是达到节点能储存的关键词上线就需要向上分裂
splitEdge(res)
}
renewParent(r) //每次分裂会导致节点位置变化,需要重新指向父级指针
}
}
return OK
}
/** Split Nodes
向上分裂 */ func splitEdge(n *node) int16 { var n1, n2 *node var i, pos int16 if n.parent == nil { n1 = MakeNode() n2 = MakeNode() n1.indexesNum = M / 2 n2.indexesNum = M - M/2 - 1 n1.parent = n n2.parent = n for i = 0; i <= M; i++ { n1.children[i] = nil n1.indexes[i] = 0 n1.vals[i] = 0 n2.children[i] = nil n2.indexes[i] = 0 n2.vals[i] = 0 } for i = 0; i <= M/2; i++ { n1.children[i] = n.children[i] n1.indexes[i] = n.indexes[i] n1.vals[i] = n.vals[i] } n2.children[0] = n.children[M/2+1] for i = M/2 + 2; i <= M; i++ { n2.children[i-M/2-1] = n.children[i] n2.indexes[i-M/2-1] = n.indexes[i] n2.vals[i] = n.vals[i] } n.indexesNum = 1 n.children[0] = n1 n.children[1] = n2 n.indexes[1] = n.indexes[M/2+1] n.vals[1] = n.vals[M/2+1] for i = 2; i <= M; i++ { n.indexes[i] = 0 n.vals[i] = 0 n.children[i] = nil } } else { pos = WhichChildNode(n) for i = n.parent.indexesNum; i > pos; i-- { n.parent.indexes[i+1] = n.parent.indexes[i] n.parent.vals[i+1] = n.parent.vals[i] n.parent.children[i+1] = n.parent.children[i] } n.parent.indexesNum++ n.parent.indexes[pos+1] = n.indexes[M/2+1] n.parent.vals[pos+1] = n.vals[M/2+1] n2 = MakeNode() n.parent.children[pos+1] = n2 for i = 0; i <= M; i++ { n2.indexes[i] = 0 n2.vals[i] = 0 n2.children[i] = nil } n2.indexesNum = M - M/2 - 1 n2.parent = n.parent n2.children[0] = n.children[M/2+1] for i = M/2 + 2; i <= M; i++ { // Initialization n2 n2.indexes[i-M/2-1] = n.indexes[i] n2.vals[i-M/2-1] = n.vals[i] n2.children[i-M/2-1] = n.children[i] } n.indexesNum = M / 2 for i = M/2 + 1; i <= M; i++ { // Initialization n1 n.indexes[i] = 0 n.vals[i] = 0 n.children[i] = nil } if n.parent.indexesNum == M { splitEdge(n.parent) } } return OK }
上面插入还算简单,接着就是删除操作,对于删除方式,首先分为叶子跟非叶子节点:
非叶子节点:如果该关键字所在的结点不是最下层的非叶子结点,则先需要把此关键字与它在B树中后继(最近右边子树)对换位置,即以指针Pi所指子树中的最小关键字Y代替Ki,然后在相应的结点中删除Y。
叶子节点:(非叶子节点需要替换到叶子节点,然后在进行下面的操作)
1、若该关键字Ki所在结点中的关键字个数大于等于m/2,则可以直接从该结点中删除该关键字和相应指针即可。(这个最简单)
2、若该关键字Ki所在结点中的关键字个数小于m/2,可以分为以下几种:
1)考虑左兄弟节点中的关键词个数,是否大于等于m/2(这个不需要递归到根节点,因为节点高度没变化)
2)考虑右兄弟节点中的关键词个数,是否大于等于m/2(这个不需要递归到根节点,因为节点高度没变化)
3)兄弟都没多余的关键词个数,那就合并(这个需要递归到根节点)
① 左兄弟(存在的情况)+ 自身(删除后剩余的关键词)+与父级节点中的一个关键词 = 合并到左兄弟节点中
② 右兄弟(存在的情况)+ 自身(删除后剩余的关键词)+与父级节点中的一个关键词 = 合并到自身节点中
//r为根节点,key为删除的关键词
func DeleteTreeNode(r *node, key int16) int16 {
if r == nil {
return ERROR
}
// 找出存在的关键词
res, pos, state := FindOfNode(r, key)
if state == FALSE {
return FALSE
}
if state == TRUE {
if res.children[0] == nil { // 如果为叶子节点
for i := pos; i < res.indexesNum; i++ {
res.indexes[i] = res.indexes[i+1]
res.vals[i] = res.vals[i+1]
res.children[i] = res.children[i+1]
}
res.indexesNum--
MergeTreeNode(res)
} else {//非叶子节点需要替换后继子节点中最小叶子节点中的最小关键词
rn := FindMinKey(res, res.children[pos], pos)
var i int16
for i = 1; i < rn.indexesNum; i++ {
rn.indexes[i] = rn.indexes[i+1]
rn.vals[i] = rn.vals[i+1]
rn.children[i] = rn.children[i+1]
}
rn.indexesNum--
MergeTreeNode(rn)
}
renewParent(r)
}
return ERROR
}
/**
合并操作
*/
func MergeTreeNode(n *node) int16 {
p := n.parent
if p == nil || p.indexesNum <= 0 {
if n.indexesNum <= 0 {
if n.children[0] != nil {
root = *n.children[0]
}
} else {
root = *n
}
root.parent = nil
return TRUE
}
if n.indexesNum >= M/2 {
return TRUE
}
// Borrow it from your brother
pos := WhichChildNode(n)
// Borrow from brother left
var i, j int16
for i = pos - 1; i >= 0; i-- {
if p.children[i] != nil && p.children[i].indexesNum > M/2 { // 左兄弟节点有多的关键词
for j = i; j < pos; j++ {
MoveLeftToRight(p.children[j], p.children[j+1], p, j+1)
}
return TRUE
}
}
// Borrow from brother right
for i = pos + 1; i <= p.indexesNum; i++ {
if p.children[i] != nil && p.children[i].indexesNum > M/2 {// 右兄弟节点有多关键词
for j = i; j > pos; j-- {
MoveRightToLeft(p.children[j], p.children[j-1], p, j)
}
return TRUE
}
}
// 兄弟节点都没多,只能合并
if pos > 0 {// 我向左兄弟合并
if p.children[pos] == nil || p.children[pos-1] == nil {
return ERROR
}
MergeParentBotherLeft(p.children[pos], p.children[pos-1], p, pos)
MergeTreeNode(p)// 递归操作
} else if pos < p.indexesNum { // 右兄弟向我合并
if p.children[pos] == nil || p.children[pos+1] == nil {
return ERROR
}
MergeParentBotherRight(p.children[pos+1], p.children[pos], p, pos+1)
MergeTreeNode(p)
}
return TRUE
}
三、总结
起初只是以为B树是简单搜索树的一种,本人也是经常刷水题的程序猿,然而却花费了近一周时间才做出来(我也不知道有没有问题,测试3到10阶),最难的是删除合并,这个思路太卡了,借鉴了各种大神图文讲解,代码研究,终于写出来了。后面有空还会研究B+树、B*树以及其他算法结构。下面附上完整代码。
package gobbk
import "fmt"
const (
// status
NOFIND int16 = -1
OK int16 = 0
TRUE int16 = 1
FALSE int16 = 2
ERROR int16 = 6
// Balanced tree of order M
M int16 = 4
nodeMinM = M/2 - 1
nodeMaxM = M - 1
)
type (
node struct {
// Number of indexes
indexesNum int16
// Do not assign zero
indexes []int16
// Custom data values
vals []int16
children []*node
parent *node
}
)
// Set a root node
var root node
func GetRoot() node {
return root
}
// Make a new node
func MakeNode() *node {
n := node{
indexesNum: 1,
indexes: make([]int16, M+1),
vals: make([]int16, M+1),
children: make([]*node, M+1),
parent: nil,
}
return &n
}
// Delete this node for the Balanced Tree Node
func DeleteTreeNode(r *node, key int16) int16 {
if r == nil {
return ERROR
}
// Find out if this node exists
res, pos, state := FindOfNode(r, key)
if state == FALSE {
return FALSE
}
if state == TRUE {
if res.children[0] == nil { // If it's a leaf node
for i := pos; i < res.indexesNum; i++ {
res.indexes[i] = res.indexes[i+1]
res.vals[i] = res.vals[i+1]
res.children[i] = res.children[i+1]
}
res.indexesNum--
MergeTreeNode(res)
} else {
rn := FindMinKey(res, res.children[pos], pos)
var i int16
for i = 1; i < rn.indexesNum; i++ {
rn.indexes[i] = rn.indexes[i+1]
rn.vals[i] = rn.vals[i+1]
rn.children[i] = rn.children[i+1]
}
rn.indexesNum--
MergeTreeNode(rn)
}
renewParent(r)
}
return ERROR
}
func FindMinKey(n *node, rn *node, pos int16) *node {
if n == nil || rn == nil {
return nil
}
if rn.children[0] == nil || rn.children[0].indexesNum == 0 {
n1 := MakeNode()
n1.indexes[1] = n.indexes[pos]
n1.vals[1] = n.vals[pos]
n.indexes[pos] = rn.indexes[1]
n.vals[pos] = rn.vals[1]
rn.indexes[1] = n1.indexes[1]
rn.vals[1] = n1.vals[1]
return rn
}
return FindMinKey(n, rn.children[0], pos)
}
/**
Merge Nodes
*/
func MergeTreeNode(n *node) int16 {
p := n.parent
if p == nil || p.indexesNum <= 0 {
if n.indexesNum <= 0 {
if n.children[0] != nil {
root = *n.children[0]
}
} else {
root = *n
}
root.parent = nil
return TRUE
}
if n.indexesNum >= M/2 {
return TRUE
}
// Borrow it from your brother
pos := WhichChildNode(n)
// Borrow from brother left
var i, j int16
for i = pos - 1; i >= 0; i-- {
if p.children[i] != nil && p.children[i].indexesNum > M/2 { // The left brother has many nodes
for j = i; j < pos; j++ {
MoveLeftToRight(p.children[j], p.children[j+1], p, j+1)
}
return TRUE
}
}
// Borrow from brother right
for i = pos + 1; i <= p.indexesNum; i++ {
if p.children[i] != nil && p.children[i].indexesNum > M/2 {
for j = i; j > pos; j-- {
MoveRightToLeft(p.children[j], p.children[j-1], p, j)
}
return TRUE
}
}
// Borrow node from parent node
if pos > 0 {
if p.children[pos] == nil || p.children[pos-1] == nil {
return ERROR
}
MergeParentBotherLeft(p.children[pos], p.children[pos-1], p, pos)
MergeTreeNode(p)
} else if pos < p.indexesNum {
if p.children[pos] == nil || p.children[pos+1] == nil {
return ERROR
}
MergeParentBotherRight(p.children[pos+1], p.children[pos], p, pos+1)
MergeTreeNode(p)
}
return TRUE
}
func MergeParentBotherRight(a *node, b *node, p *node, pos int16) {
var i int16
/*------*/
b.indexesNum++
b.indexes[b.indexesNum] = p.indexes[pos]
b.vals[b.indexesNum] = p.vals[pos]
b.children[b.indexesNum] = a.children[0]
/*------*/
for i = pos; i < p.indexesNum; i++ {
p.indexes[i] = p.indexes[i+1]
p.vals[i] = p.vals[i+1]
p.children[i] = p.children[i+1]
}
p.indexesNum--
/*------*/
for i = 1; i <= a.indexesNum; i++ {
b.indexesNum++
b.indexes[b.indexesNum] = a.indexes[i]
b.vals[b.indexesNum] = a.vals[i]
b.children[b.indexesNum] = a.children[i]
}
a.indexesNum = 0
}
func MergeParentBotherLeft(a *node, b *node, p *node, pos int16) {
var i int16
/*------*/
b.indexesNum++
b.indexes[b.indexesNum] = p.indexes[pos]
b.vals[b.indexesNum] = p.vals[pos]
b.children[b.indexesNum] = a.children[0]
/*------*/
for i = pos; i < p.indexesNum; i++ {
p.indexes[i] = p.indexes[i+1]
p.vals[i] = p.vals[i+1]
p.children[i] = p.children[i+1]
}
p.indexesNum--
/*------*/
for i = 1; i <= a.indexesNum; i++ {
b.indexesNum++
b.indexes[b.indexesNum] = a.indexes[i]
b.vals[b.indexesNum] = a.vals[i]
b.children[b.indexesNum] = a.children[i]
}
a.indexesNum = 0
}
func MoveRightToLeft(a *node, b *node, p *node, pos int16) {
var i int16
/*------*/
p.indexesNum++
p.children[p.indexesNum] = p.children[p.indexesNum-1]
for i = p.indexesNum; i > pos+1; i-- {
p.indexes[i] = p.indexes[i-1]
p.vals[i] = p.vals[i-1]
p.children[i-1] = p.children[i-2]
}
/*------*/
p.indexes[pos+1] = a.indexes[1]
p.vals[pos+1] = a.vals[1]
p.children[pos] = a.children[0]
for i = 1; i < a.indexesNum; i++ {
a.indexes[i] = a.indexes[i+1]
a.vals[i] = a.vals[i+1]
a.children[i-1] = a.children[i]
}
a.children[a.indexesNum-1] = a.children[a.indexesNum]
a.indexesNum--
/*------*/
b.indexesNum++
b.indexes[b.indexesNum] = p.indexes[pos]
b.vals[b.indexesNum] = p.vals[pos]
b.children[b.indexesNum] = p.children[pos]
/*------*/
for i = pos; i < p.indexesNum; i++ {
p.indexes[i] = p.indexes[i+1]
p.vals[i] = p.vals[i+1]
p.children[i] = p.children[i+1]
}
p.indexesNum--
}
func MoveLeftToRight(a *node, b *node, p *node, pos int16) {
var i int16
/*------*/
p.indexesNum++
for i = p.indexesNum; i > pos; i-- {
p.indexes[i] = p.indexes[i-1]
p.vals[i] = p.vals[i-1]
p.children[i] = p.children[i-1]
}
/*------*/
p.indexes[pos] = a.indexes[a.indexesNum]
p.vals[pos] = a.vals[a.indexesNum]
p.children[pos] = a.children[a.indexesNum]
a.indexesNum--
/*------*/
b.indexesNum++
for i = b.indexesNum; i > 0; i-- {
b.indexes[i] = b.indexes[i-1]
b.vals[i] = b.vals[i-1]
b.children[i] = b.children[i-1]
}
b.indexes[1] = p.indexes[pos+1]
b.vals[1] = p.vals[pos+1]
b.children[0] = p.children[pos]
/*------*/
p.children[pos] = p.children[pos+1]
for i = pos + 1; i < p.indexesNum; i++ {
p.indexes[i] = p.indexes[i+1]
p.vals[i] = p.vals[i+1]
p.children[i] = p.children[i+1]
}
p.indexesNum--
}
// r为根节点指针,key为插入关键词,value是插入的数据 返回state状态
// Insert a new node for the Balanced Tree Node
func InsertTreeNode(r *node, key int16, value int16) int16 {
if r.indexesNum == 0 { // The root node is empty
fmt.Println("root is empty node", r)
r.indexes = make([]int16, M+1, M+1)
r.vals = make([]int16, M+1, M+1)
r.children = make([]*node, M+1, M+1)
var i int16
for i = 0; i <= M; i++ {
r.indexes[0] = 0
r.vals[i] = 0
r.children[i] = nil
}
r.indexesNum++
r.indexes[1] = key
r.vals[1] = value
} else {
// Find out if this node exists
res, pos, state := FindOfNode(r, key)
if state == TRUE {
fmt.Println("This n node is exist!")
return ERROR
}
if state == FALSE {
res.indexesNum++
var i int16
for i = res.indexesNum; i > pos; i-- {
res.indexes[i] = res.indexes[i-1]
res.children[i] = res.children[i-1]
res.vals[i] = res.vals[i-1]
}
res.indexes[pos] = key
res.vals[pos] = value
res.children[pos] = nil
if res.indexesNum == M {
splitEdge(res)
}
renewParent(r)
}
}
return OK
}
/**
Split Nodes
*/
func splitEdge(n *node) int16 {
var n1, n2 *node
var i, pos int16
if n.parent == nil {
n1 = MakeNode()
n2 = MakeNode()
n1.indexesNum = M / 2
n2.indexesNum = M - M/2 - 1
n1.parent = n
n2.parent = n
for i = 0; i <= M; i++ {
n1.children[i] = nil
n1.indexes[i] = 0
n1.vals[i] = 0
n2.children[i] = nil
n2.indexes[i] = 0
n2.vals[i] = 0
}
for i = 0; i <= M/2; i++ {
n1.children[i] = n.children[i]
n1.indexes[i] = n.indexes[i]
n1.vals[i] = n.vals[i]
}
n2.children[0] = n.children[M/2+1]
for i = M/2 + 2; i <= M; i++ {
n2.children[i-M/2-1] = n.children[i]
n2.indexes[i-M/2-1] = n.indexes[i]
n2.vals[i] = n.vals[i]
}
n.indexesNum = 1
n.children[0] = n1
n.children[1] = n2
n.indexes[1] = n.indexes[M/2+1]
n.vals[1] = n.vals[M/2+1]
for i = 2; i <= M; i++ {
n.indexes[i] = 0
n.vals[i] = 0
n.children[i] = nil
}
} else {
pos = WhichChildNode(n)
for i = n.parent.indexesNum; i > pos; i-- {
n.parent.indexes[i+1] = n.parent.indexes[i]
n.parent.vals[i+1] = n.parent.vals[i]
n.parent.children[i+1] = n.parent.children[i]
}
n.parent.indexesNum++
n.parent.indexes[pos+1] = n.indexes[M/2+1]
n.parent.vals[pos+1] = n.vals[M/2+1]
n2 = MakeNode()
n.parent.children[pos+1] = n2
for i = 0; i <= M; i++ {
n2.indexes[i] = 0
n2.vals[i] = 0
n2.children[i] = nil
}
n2.indexesNum = M - M/2 - 1
n2.parent = n.parent
n2.children[0] = n.children[M/2+1]
for i = M/2 + 2; i <= M; i++ { // Initialization n2
n2.indexes[i-M/2-1] = n.indexes[i]
n2.vals[i-M/2-1] = n.vals[i]
n2.children[i-M/2-1] = n.children[i]
}
n.indexesNum = M / 2
for i = M/2 + 1; i <= M; i++ { // Initialization n1
n.indexes[i] = 0
n.vals[i] = 0
n.children[i] = nil
}
if n.parent.indexesNum == M {
splitEdge(n.parent)
}
}
return OK
}
// Renew Parent
func renewParent(n *node) int16 {
if n == nil {
return ERROR
}
var i int16
for i = 0; i <= n.indexesNum; i++ {
if n.children[i] != nil {
n.children[i].parent = n
renewParent(n.children[i])
}
}
return TRUE
}
// Find the number of child nodes it is in
func WhichChildNode(n *node) int16 {
if n == nil {
return 0
}
var i int16
for i = 0; i <= n.parent.indexesNum; i++ {
if n.parent.children[i] == n {
return i
}
}
return 0
}
/**
Find this position of this node
@param r (This is root node)
@param k (This is the node keyword to be found)
@return res (This is the node found)
@return pos (This is the node position found)
@return state
*/
func FindOfNode(r *node, k int16) (res *node, pos int16, state int16) {
pos = 0
if r == nil {
return res, pos, FALSE
}
q := r
for q != nil {
var i int16 = 1
key := q.indexes[i]
for i <= q.indexesNum {
if k == key { // Find this n node
res = q
pos = i
return res, pos, TRUE
}
if k > key {
if i == q.indexesNum {
if q.children[i] == nil {
res = q
pos = i + 1
return res, pos, FALSE
}
q = q.children[i]
break
}
i++
key = q.indexes[i]
continue
}
if k < key {
if q.children[i-1] == nil {
res = q
pos = i
return res, pos, FALSE
}
q = q.children[i-1]
break
}
}
}
return res, pos, ERROR
}
// Traversing tree nodes in middle order
func PrintTreeNode(n *node) {
arr := []*node{n}
iarr := []int16{1}
var preH int16 = 1
index := 0
for index < len(arr) && arr[index] != nil {
if iarr[index] != preH {
preH = iarr[index]
fmt.Println("")
}
fmt.Print("[")
var j int16
for j = 1; j <= arr[index].indexesNum; j++ {
fmt.Print(" ", arr[index].indexes[j], " ")
}
fmt.Print("]")
for j = 0; j <= arr[index].indexesNum; j++ {
if arr[index].children[j] == nil {
break
}
arr = append(arr, arr[index].children[j])
iarr = append(iarr, preH+1)
}
index++
}
fmt.Println("")
return
}
func InsertTest() {
//40, 80, 30, 50, 90, 25, 35, 44, 46, 55, 82, 85, 93
arr := []int16{50, 30, 80, 20, 40, 60, 90, 10, 25, 35, 44, 55, 85, 93, 82, 46,50}
for i := 0; i < len(arr); i++ {
InsertTreeNode(&root, arr[i], arr[i])
fmt.Println(" i:", i, ",insert:", arr[i])
PrintTreeNode(&root)
}
}
func DeleteTest() {
arr := []int16{50, 30, 80, 20, 40, 60, 90, 10, 25, 35, 44, 55, 85, 93, 82, 46}
for i := 0; i < len(arr); i++ {
DeleteTreeNode(&root, arr[i])
fmt.Println(" i:", i, ",delete:", arr[i])
PrintTreeNode(&root)
}
}

浙公网安备 33010602011771号