BTree特性
1.m阶的树,节点除root外,会存在[m/2,m]个child,存在[m/2-1,m-1]key,在现实时存在n个key则存在(n+1)个child
他们的布局
child key child key child …
例子阶为3,
string printArray() {
std::stringstream info;
print(getRoot(),info);
info << "\n";
return info.str();
}
void print(node_type_ptr _node,std::stringstream& _info) {
if (_node == nullptr)return;
auto child_it = _node->getChilds().begin();
auto child_it_end = _node->getChilds().end();
auto key_it = _node->getKeys().begin();
print(*child_it, _info);
++child_it;
for (; child_it != child_it_end;key_it++,child_it++) {
_info << *key_it<<" ";
print(*child_it, _info);
}
}
遍历的结果:1 2 3 4 5
2.插入例子
如上图:
(1)insert 6:
<1>首先会从root开始找是否是叶子节点,如果不是,则根据插入的值6找到下一个叶子节点即5,然后插入
<2>然后节点5判断key的个数是否超过m-1,即m-1=2,所以|5,6|只是两个,并不超过,不需要调整树
最后的结果是
(2)插入10
<1>首先会找到合适的叶子节点,|5,6|,然后插入变成|5,6,10|
<2>|5,6,10|大于2,所以需要调整树,
首先将此节点中间的元素(6)提取出来,加入parent节点,左右部分成为新节点,左节点,和右节点
6加入|2,4|之中,成为|2,4,6|,然后此节点key的个数是3,所以重复<2>,4被提取出来成为父元素
(3)现在插入9,
(4)现在插入8
找到的节点|9,10|,加入后|8,9,10|,然后分裂|8| |9| |10|,|9|去到|6|的位置成为|6,9|
3.删除例子
(1)删除6,找到节点|6,9|,因为不是叶子节点,所以找到叶子找到|8|,然后将|6,9| --> |8,9|
(2)然后在节点|8,| 删除8, ,|8| --> ||
(3)先看左兄弟是否存在,如果不存在则右兄弟
(4)合并节点(当前叶节点和兄弟节点),如果兄弟节点 key_size>min_size,则将兄弟节点的元素移动到父节点,父节点的元素移到当前的删除元素的叶节点
key_size==min_size,则将父节点的元素移到兄弟节点;
现在找到左兄弟,|5| ,size==min_size,所以将父节点|6,9|的元素6,移动到|5|变成|5,6|
例子删除2,叶子节点|3|,|2| --> |3|,现在删除叶子节点|3|
兄弟节点|1| ,size==min_size,|3|中3–>|1,3|
现在调整|NuLL|,
现在删除3
因为|1,3| --> |1| 节点的size=1 ,size>=1,所以不需要调整
现在删除1
因为|1|–>|| ,size<min_size,所以需要调整树,
因为|5,6|, size>min_size,所以兄弟节点移动元素个父元素,父节点移动给|1|
insert
void insert(const_value_type_refrence _key) {
LOGXA("insert key: ", _key);
if (getRoot() == nullptr) {
getRoot() = new node_type;
getNowNodeSize() += 1;
getRoot()->insertKey(_key, nullptr, nullptr);
return;
}
node_type_ptr node = nullptr;
value_type parent_key;
{
node = findNextleafNode(getRoot(), _key, parent_key);
if (node == nullptr)return;
}
{
//while (!node->isLeaf()) {
// if (node->isExistKey(_key))return;
// node = node->next(_key);
//}
}
if (node->isExistKey(_key))return;
LOGXD("1.find and was to leaf:", getNodeKey(node));
node->insertKey(_key, nullptr, nullptr);
LOGXD("2.insert key,now node:", getNodeKey(node));
//3.
adjustmentAfterInsert(node);
LOGXT("now node size", VAR_DATA(getNowNodeSize()));
LOGXD(printTree());
LOGXD(printArray());
}
void adjustmentAfterInsert(node_type_ptr _node) {
if (_node == nullptr)return;
while (_node->getKeys().size() >= m_rank) {
LOGXA("need adjust node:", VAR_DATA(getNodeKey(_node)));
node_type_ptr child_left = splitNode(_node, 0, (m_rank - 1) / 2);
node_type_ptr child_right = splitNode(_node, (m_rank - 1) / 2+1,m_rank - (m_rank - 1) / 2 -1);
value_type need_to_parent_value = _node->at((m_rank - 1) / 2);
delete _node;
getNowNodeSize() -= 1;
_node = child_left->getParent();
if (_node == nullptr) {
getRoot() = _node = new node_type;
getNowNodeSize() += 1;
child_left->getParent() = child_right->getParent() = getRoot();
}
_node->insertKey(need_to_parent_value, child_left, child_right);
}
}
node_type_ptr splitNode(node_type_ptr _node, std::size_t _start_loc, std::size_t _len) {
LOGXA("split node,start location:len", _start_loc, ":", _len, "node:", getNodeKey(_node));
if (_node == nullptr)return nullptr;
auto all_len = _node->getKeys().size();
if (all_len < _start_loc + _len)return nullptr;
node_type_ptr new_node = new node_type;
getNowNodeSize() += 1;
new_node->getParent() = _node->getParent();
auto it_key = _node->getKeys().begin();
auto it_key_end = _node->getKeys().end();
auto it_child = _node->getChilds().begin();
while (_start_loc--){
it_key++; it_child++;
}
new_node->getChilds().push_back(*it_child);
std::size_t now_move_size = 0;
while (now_move_size < _len) {
new_node->getKeys().push_back(*it_key);
LOGXD("move key", *it_key,"now new node:",getNodeKey(new_node));
++it_key;
++it_child;
now_move_size++;
new_node->getChilds().push_back(*it_child);
}
LOGXD("1.move end:", VAR_DATA(getNodeKey(new_node)));
new_node->updateParent();
return new_node;
}
node_type_ptr findNextleafNode(node_type_ptr _node, const_value_type_refrence _key, value_type& parent_key) {
node_type_ptr node = _node;
while (node) {
auto key_it = node->getKeys().begin();
auto key_it_end = node->getKeys().end();
auto child_it = node->getChilds().begin();
while (key_it != key_it_end) {
if (*key_it > _key) { break; }//because it is left
key_it++;
child_it++;
}
if (key_it != key_it_end) parent_key = *key_it;
if (*child_it == nullptr)return node;
node = *child_it;
}
return nullptr;
}
erase
void erase(value_type _key) {
LOGXA("erase key:", _key);
node_type_ptr node = findNode(_key);
if (node == nullptr)return;
if (node->isLeaf()==false) {
value_type next_key;
node_type_ptr next_node = findNextleafNode(node,_key,next_key);
node->replace(_key, next_key);
_key = next_key;
node = next_node;
}
LOGXD("1.go to leaf:", getNodeKey(node));
node->eraseKey(_key);
node->eraseChild(nullptr);
adjustmentAfterErase(node);
LOGXD(printTree());
LOGXT("now node size", VAR_DATA(getNowNodeSize()));
}
void mergeNode(node_type_ptr _node, node_type_ptr _bro_node, value_type _parent_key, bool _is_left) {
LOGXD(getNodeKey(_node), getNodeKey(_bro_node), VAR_DATA(_parent_key), VAR_DATA(_is_left));
node_type_ptr parent = _node->getParent();
int min_size = ceil(m_rank / 2.0) - 1;
if (_bro_node->getKeys().size() > min_size) {
//bro will split key x,parent->_node_key,x->parent
LOGXD("1.bro will split key x,parent->_node_key,x->parent");
value_type replace_key = _is_left ? *(_bro_node->getKeys().rbegin()) : *(_bro_node->getKeys().begin());
node_type_ptr replace_child= _is_left ? *(_bro_node->getChilds().rbegin()) : *(_bro_node->getChilds().begin());
_bro_node->eraseKey(replace_key);
_bro_node->eraseChild(replace_child);
parent->replace(_parent_key, replace_key);
if (_is_left) {
_node->getKeys().push_front(_parent_key);
_node->getChilds().push_front(replace_child);
}
else {
_node->getKeys().push_back(_parent_key);
_node->getChilds().push_back(replace_child);
}
_node->updateParent();
LOGXD("2.now", VAR_DATA(getNodeKey(_node)), VAR_DATA(getNodeKey(_bro_node)), VAR_DATA(getNodeKey(parent)));
}
else {
//_bro_node size == min_size,parent will split key x to bro, x->bro_key
LOGXD("1._bro_node size == min_size,parent will split key x to bro, x->bro_key");
parent->eraseKey(_parent_key);
parent->eraseChild(_node);
if (_is_left) {
_bro_node->getKeys().push_back(_parent_key);
_bro_node->getKeys().splice(_bro_node->getKeys().end(), _node->getKeys());
_bro_node->getChilds().splice(_bro_node->getChilds().end(), _node->getChilds());
}
else {
_bro_node->getKeys().push_front(_parent_key);
_bro_node->getKeys().splice(_bro_node->getKeys().begin(), _node->getKeys());
_bro_node->getChilds().splice(_bro_node->getChilds().begin(), _node->getChilds());
}
parent->updateParent();
_bro_node->updateParent();
delete _node;
getNowNodeSize() -= 1;
LOGXD("2.now", VAR_DATA(getNodeKey(_bro_node)), VAR_DATA(getNodeKey(parent)));
}
}
void adjustmentAfterErase(node_type_ptr _node) {
//1.deal root
LOGXD("adjustment tree ", VAR_DATA(getNodeKey(_node)));
if (_node == nullptr)return;
if (_node == getRoot()) {
auto size = getRoot()->getKeys().size();
if (size == 0) {
getRoot() = *(getRoot()->getChilds().begin());
if (getRoot())getRoot()->getParent()=nullptr;
delete _node;
getNowNodeSize() -= 1;
}
return;
}
//2.merge node
node_type_ptr parent = _node->getParent();
int min_size = ceil(m_rank / 2.0) - 1;
if (_node->getKeys().size() >= min_size) {
LOGXD(printTree());
return;
}
LOGXD("start merge node");
value_type parent_key = 0;
node_type_ptr bro_node = findBroNode(_node,parent_key,true);
if (bro_node)mergeNode(_node, bro_node, parent_key, true);
else {
bro_node = findBroNode(_node, parent_key, false);
mergeNode(_node, bro_node, parent_key, false);
}
//3.
adjustmentAfterErase(parent);
}