B+树动画演示
https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html

package main

/*
B+树动画演示
https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html
*/
import (
	"fmt"
)

const (
	MAX_KEYS = 3 // 每个节点的最大键数量
)

type BPlusTree struct {
	root *Node
}

type Node struct {
	keys     []int
	leaf     bool
	children []*Node
}

// 创建一个新的节点
func newNode(leaf bool) *Node {
	return &Node{
		keys:     make([]int, 0),
		leaf:     leaf,
		children: make([]*Node, 0),
	}
}

// 初始化B+树
func NewBPlusTree() *BPlusTree {
	root := newNode(true)
	return &BPlusTree{root: root}
}
func (tree *BPlusTree) PrintTree() {
	fmt.Println("B+ 树结构:")
	printNode(tree.root, 0, "", -1)
}

func printNode(node *Node, level int, prefix string, childNum int) {
	if childNum >= 0 {
		fmt.Printf("%s子节点 %d: ", prefix, childNum)
	} else {
		fmt.Printf("%s", prefix)
	}
	fmt.Printf("层级 %d: ", level)
	for i, k := range node.keys {
		fmt.Printf("%d", k)
		if i < len(node.keys)-1 {
			fmt.Print(" | ")
		}
	}
	fmt.Println()

	if !node.leaf {
		childPrefix := prefix + "│   "
		for i, child := range node.children {
			if i == len(node.children)-1 {
				fmt.Printf("%s└───", prefix)
				childPrefix = prefix + "    "
			} else {
				fmt.Printf("%s├───", prefix)
			}
			printNode(child, level+1, childPrefix, i)
		}
	}
}

func (tree *BPlusTree) Search(key int) bool {
	fmt.Printf("搜索键值 %d:\n", key)
	return searchNode(tree.root, key, 0, "", -1)
}

func searchNode(node *Node, key int, level int, prefix string, childNum int) bool {
	if childNum >= 0 {
		fmt.Printf("%s子节点 %d: ", prefix, childNum)
	} else {
		fmt.Printf("%s", prefix)
	}
	fmt.Printf("层级 %d: 检查节点,键值为 [", level)
	for i, k := range node.keys {
		fmt.Printf("%d", k)
		if i < len(node.keys)-1 {
			fmt.Print(" | ")
		}
	}
	fmt.Println("]")

	if node.leaf {
		for _, k := range node.keys {
			if k == key {
				fmt.Printf("%s  在叶子节点中找到键值 %d\n", prefix, key)
				return true
			}
		}
		fmt.Printf("%s  在叶子节点中未找到键值 %d\n", prefix, key)
		return false
	}

	for i := 0; i < len(node.keys); i++ {
		if key < node.keys[i] {
			fmt.Printf("%s  键值 %d < %d,移动到子节点 %d\n", prefix, key, node.keys[i], i)
			return searchNode(node.children[i], key, level+1, prefix+"    ", i)
		}
	}
	lastChild := len(node.keys)
	fmt.Printf("%s  键值 %d >= 节点中所有键值,移动到子节点 %d\n", prefix, key, lastChild)
	return searchNode(node.children[lastChild], key, level+1, prefix+"    ", lastChild)
}

// 插入一个键
func (tree *BPlusTree) Insert(key int) {
	root := tree.root
	if len(root.keys) == MAX_KEYS {
		newRoot := newNode(false)
		newRoot.children = append(newRoot.children, root)
		tree.splitChild(newRoot, 0)
		tree.root = newRoot
	}

	tree.insertNonFull(root, key)
}

func (tree *BPlusTree) insertNonFull(node *Node, key int) {
	if node.leaf {
		node.keys = append(node.keys, key)
		sortKeys(node)
		return
	}

	// 找到插入位置
	i := len(node.keys) - 1
	for i >= 0 && key < node.keys[i] {
		i--
	}
	i++

	// 插入到子节点
	child := node.children[i]
	if len(child.keys) == MAX_KEYS {
		tree.splitChild(node, i)
		if key > node.keys[i] {
			i++
		}
	}
	tree.insertNonFull(node.children[i], key)
}

func (tree *BPlusTree) splitChild(parent *Node, index int) {
	node := parent.children[index]
	newNode := newNode(node.leaf)

	// 将中间的键提升到父节点
	mid := len(node.keys) / 2
	parent.keys = append(parent.keys, 0)
	copy(parent.keys[index+1:], parent.keys[index:])
	parent.keys[index] = node.keys[mid]

	// 将子节点分割
	parent.children = append(parent.children, nil)
	copy(parent.children[index+2:], parent.children[index+1:])
	parent.children[index+1] = newNode

	// 将右半部分的键和子节点转移到新的节点
	newNode.keys = append(newNode.keys, node.keys[mid+1:]...)
	node.keys = node.keys[:mid]
	if !node.leaf {
		newNode.children = append(newNode.children, node.children[mid+1:]...)
		node.children = node.children[:mid+1]
	}
}

// 排序节点的键
func sortKeys(node *Node) {
	for i := 1; i < len(node.keys); i++ {
		for j := i; j > 0 && node.keys[j] < node.keys[j-1]; j-- {
			node.keys[j], node.keys[j-1] = node.keys[j-1], node.keys[j]
		}
	}
}

func main() {
	tree := NewBPlusTree()

	keys := []int{10, 20, 5, 6, 15, 30, 40, 50, 60}
	for _, key := range keys {
		tree.Insert(key)
	}

	fmt.Println("B+ Tree structure:")
	tree.PrintTree()

	fmt.Println("\nSearch operations:")
	searchKeys := []int{15, 25, 40, 7}
	for _, key := range searchKeys {
		if tree.Search(key) {
			fmt.Printf("Found %d\n", key)
		} else {
			fmt.Printf("%d not found\n", key)
		}
		fmt.Println()
	}
}