背景
这几天看mysql索引的知识,了解到BTree数据结构,无聊想挑战一下去实现一下,Btree的数据结构特点我就不介绍,具体的图解请查看这个链接https://blog.youkuaiyun.com/li_canhui/article/details/85305147,我比较笨,不会使用画图软件😁
<?php
//存放每一个数据的容器
class Ceil
{
public $index;//数据
//仅当一个Unit的第一个Ceil需要使用左地址进行数据传递
public $left;//左地址
public $right;//右地址
public function __construct($index)
{
$this->index = $index;
}
}
//
class Unit
{
public $parent;//父Unit地址,默认为null
public $items;//存储Ceil的队列
public static $fork_num;//叉值
public function __construct($items)
{
$this->items = $items;
}
//添加ceil
public function add_ceil($ceil){
//去找到具体的位置
$position_message = $this->find_node($this,$ceil);
$unit = $position_message['unit'];
//向该位置添加ceil
array_splice($unit->items,$position_message['position'],0,[$ceil]);
//校验是否需要进行当前Unit进行分裂操作
if(count($unit->items) == self::$fork_num){
$this->division($unit);
}
return $this;
}
//min -> max sort 插入ceil的值与队列进行排序,返回插入ceil所需要点位置及其unit实例
public function find_node(Unit $unit,Ceil $ceil){
$pointer_position = null;
$pointer_item = null;
$items = $unit->items;
//获取排序位置
$pointer = $this->get_sort($items,$ceil);
$pointer_position = $pointer['position'];
$pointer_item = $pointer['item'];
//返回0位置,切当前unit的第一个ceil存在左unit,则递归查找
if($pointer_position == 0 && $pointer_item->left != null){
$left_unit = $pointer_item->left;
return $position_message = $this->find_node($left_unit,$ceil);
}
//非0位置,切当前unit前一个位置存在右unit,则递归查找
if($pointer_position > 0 && $pointer_item->right != null){
$right_unit = $pointer_item->right;
return $position_message = $this->find_node($right_unit,$ceil);
}
return ['unit' => $unit,'position' => $pointer_position];
}
//获取插入ceil在当前unit中的位置
public function get_sort($items,$ceil,$position_limit=false){
$pointer_position = $pointer_item = false;
if(($count = count($items)) == 1){
$pointer_position = $items[0]->index > $ceil->index ? 0 : 1 ;
$pointer_item = $items[0];
}else{
foreach($items as $position => $item){
$pointer_position = $position;
$pointer_item = $item;
if($position == $count -1){
$pointer_position++;
break;
}
if($items[$position]->index > $ceil->index){
break;
}
if($items[$position]->index < $ceil->index && $items[$position+1]->index > $ceil->index){
$pointer_position++;
break;
}
}
}
if(!$position_limit){
return [
'position' => $pointer_position,
'item' => $pointer_item
];
}
return $pointer_position;
}
//执行分裂操作
public function division($unit){
//当前节点是根节点
if($unit->parent == null){
$left_ceil = array_slice($unit->items,0,(self::$fork_num-1)/2);
$middle_ceil = array_slice($unit->items,(self::$fork_num-1)/2,1);
$right_ceil = array_slice($unit->items,(self::$fork_num+1)/2);
$unit->items = $middle_ceil;
$left_unit = new Unit($left_ceil);
$right_unit = new Unit($right_ceil);
$middle_ceil[0]->left = $left_unit;
//校验中值ceil是否存在右unit,是则将其挂载分裂的右unit的第一个ceil的左子节点
if($middle_ceil[0]->right){
$tmp = $middle_ceil[0]->right;
$right_unit->items[0]->left = $tmp;
}
$middle_ceil[0]->right = $right_unit;
$left_unit->parent = $right_unit->parent = $unit;
}else{
//分裂当前节点存在父节点
$parent = $unit->parent;
$left_ceil = array_slice($unit->items,0,(self::$fork_num-1)/2);
$middle_ceil = array_slice($unit->items,(self::$fork_num-1)/2,1);
$right_ceil = array_slice($unit->items,(self::$fork_num+1)/2);
$left_unit = new Unit($left_ceil);
$right_unit = new Unit($right_ceil);
$inserted_parent = $this->insert_parent($parent,$middle_ceil[0],$left_unit,$right_unit);
//校验分裂后的父节点是否需要在此分裂
if(count($inserted_parent->items) == Unit::$fork_num){
$this->division($inserted_parent);
}
}
}
public function insert_parent($parent,$ceil,$left_unit,$right_unit){
$position = $this->get_sort($parent->items,$ceil,true);
//校验中值ceil是否存在右unit,是则将其挂载分裂的右unit的第一个ceil的左子节点
if($ceil->right){
$tmp = $ceil->right;
$right_unit->items[0]->left = $tmp;
}
$ceil->right = $right_unit;
//判断分裂后的节点插入父unit后是否是队列的最左侧,仅当左端分裂存在此现象
if($position != 0){
$parent->items[$position-1]->right = $left_unit;
}else{
//左端分裂切中间值是父节点队列的最左值,则将分裂前的左右unit均挂载在中间节点
$ceil->left = $left_unit;
$parent->items[$position]->left = null;
}
$left_unit->parent = $right_unit->parent = $parent;
array_splice($parent->items,$position,0,[$ceil]);
return $parent;
}
}
//
class BTree
{
public $root;
//初始化根节点unit
public function __construct($root,$fork_num)
{
Unit::$fork_num = $fork_num;
$this->root = $root;
}
//执行数据填充动作
public function format($data){
foreach($data as $index){
$ceil = new Ceil($index);
$this->root = $this->root->add_ceil($ceil);
}
return $this;
}
}
$data = [2,1,7,6,11,4,8,13,10,5,17,9,16,20,3,12,14,18,19,15];
$root = new Unit([new Ceil(array_shift($data))]);
$fork_num = 5;
$b_tree_root = new BTree($root,$fork_num);
$b_tree = $b_tree_root->format($data);
var_dump($b_tree);