0
点赞
收藏
分享

微信扫一扫

BTree

追风骚年 2022-04-24 阅读 71
c++btree

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);
	}
举报

相关推荐

0 条评论