B+tree

爱跑步的乌龟發表於2024-07-20
package main

import "fmt"

type BPlustree map[int]node //定義

func NewBplusTree() *BPlustree {
    bt := BPlustree{}               //初始化
    leaf := NewLeafNode(nil)        //葉子節點
    r := NewinteriorNode(nil, leaf) //中間節點
    leaf.parent = r                 //設定父親節點
    bt[-1] = r                      //根節點
    bt[0] = leaf
    return &bt
}

//返回根節點
func (bpt *BPlustree) Root() node {
    return (*bpt)[-1]
}

//處理第一個節點
func (bpt *BPlustree) First() node {
    return (*bpt)[0]
}

//統計數量
func (bpt *BPlustree) Count() int {
    count := 0
    leaf := (*bpt)[0].(*LeafNode)
    for {
        count += leaf.CountNum() //數量疊加
        if leaf.next == nil {
            break
        }
        leaf = leaf.next
    }
    return count
}

func (bpt *BPlustree) Values() []*LeafNode {
    nodes := make([]*LeafNode, 0) //開闢節點
    leaf := (*bpt)[0].(*LeafNode)
    for {
        nodes = append(nodes, leaf) //資料節點疊加
        if leaf.next == nil {
            break
        }
        leaf = leaf.next
    }
    return nodes
}

//查詢資料
func (bpt *BPlustree) Search(key int) (string, bool) {
    kv, _, _ := search((*bpt)[-1], key) //查詢
    if kv == nil {
        return "", false
    } else {
        return kv.value, true
    }
}

//搜尋資料
func search(n node, key int) (*kv, int, *LeafNode) {
    curr := n
    oldindex := -1
    for {
        switch t := curr.(type) {
        case *LeafNode: //葉子節點搜尋
            i, ok := t.find(key)
            if !ok {
                return nil, oldindex, t
            } else {
                return &t.kvs[i], oldindex, t
            }
        case *interiorNode:
            i, _ := t.find(key) //中間節點查詢
            curr = t.kcs[i].child
            oldindex = i
        default:
            panic("異常節點")
        }
    }

}

//    1   6
//12345  6789

func (bpt *BPlustree) Insert(key int, value string) {
    //插入之前,確定插入的位置
    _, oldindex, leaf := search((*bpt)[-1], key)
    p := leaf.Parent() //儲存父親節點
    //插入葉子節點,判斷是否分裂
    mid, nextleaf, bump := leaf.insert(key, value)
    if !bump { //沒有分裂,直接返回
        return
    }
    //f分裂的節點插入B+樹
    (*bpt)[mid] = nextleaf
    //中間節點
    var midnode node
    midnode = leaf
    p.kcs[oldindex].child = leaf.next    //設定父親節點
    leaf.next.SetParent(p)               //分裂的節點設定父親節點
    interior, interiorP := p, p.Parent() //獲取中間點解,父親節點

    //平衡過程,迭代向上判斷,是否需要平衡
    for {
        var oldindex int              //儲存老的索引
        var newinterior *interiorNode //新的節點
        //判斷是否到達根節點
        isRoot := interiorP == nil
        if !isRoot {
            oldindex, _ = interiorP.find(key) //查詢
        }
        //葉子節點分裂後的中間節點傳入父親的中間節點,傳入分裂
        mid, newinterior, bump = interior.insert(mid, midnode)
        if !bump {
            return
        }
        (*bpt)[newinterior.kcs[0].key] = newinterior //插入填充好了map
        if !isRoot {
            interiorP.kcs[oldindex].child = newinterior //沒有到大根節點,直接插入父親節點
            newinterior.SetParent(interiorP)
            midnode = interior

        } else {
            //更新節點
            (*bpt)[interior.kcs[0].key] = (*bpt)[-1]       //備份根節點
            (*bpt)[-1] = NewinteriorNode(nil, newinterior) //根節點插入新的根節點
            node := (*bpt)[-1].(*interiorNode)
            node.insert(mid, interior) //重新插入
            (*bpt)[-1] = node
            newinterior.SetParent(node) //設定父親節點

        }
        interior, interiorP = interiorP, interior.Parent()

    }

}

func main() {
    bpt := NewBplusTree()
    for i := 0; i < 250000; i++ {
        bpt.Insert(i, "x")
    }
    fmt.Println(bpt.Count())
    fmt.Println(bpt.Search(3))
}