数据结构:神奇的B树实现解析(有图有代码有真相!!!)

一、B树引入

二叉搜索树、平衡二叉树、红黑树都是动态查找树,典型的二叉搜索树结构,查找的时间复杂度和树的高度相关O(log2N)。


1)数据杂乱无章——-线性查找–O(n)

2)数据有序——-二分查找 —O(log 2 n)  最差退化成单支树—–线性结构

3)二叉搜索树、AVL树、红黑树 ——–O(log2 n)

数据一般保存在磁盘上,若数据量过大不能全部加载到内存,为了访问所有数据,使用如下搜索树结构保存数据:树的结点中保存权值和磁盘的地址

《数据结构:神奇的B树实现解析(有图有代码有真相!!!)》

那如何加速对数据的访问速度呢?

提高I/O的时间

降低树的高度–平衡多叉树

二、B树定义


1970年,R.Bayer和E.mccreight提出了一种适合外查找的树,它是一种平衡的多叉树,称为B树。
(有些地方写的是B-树,注意不要误读成”B减树”)
一棵M阶(M>2)的B树,是一棵平衡的M路平衡搜索树,可以是空树或者满足一下性质:
1. 根节点至少有两个孩子
2. 每个非根节点至少有M/2(上取整)个孩子,至多有M个孩子
3. 每个非根节点至少有M/2-1(上取整)个关键字,至多有M-1个关键字,并且以升序排列

4. key[i]和key[i+1]之间的孩子节点的值介于key[i]、key[i+1]之间


一次插入的过程:53, 75, 139, 49, 145, 36, 101


《数据结构:神奇的B树实现解析(有图有代码有真相!!!)》

《数据结构:神奇的B树实现解析(有图有代码有真相!!!)》

《数据结构:神奇的B树实现解析(有图有代码有真相!!!)》

《数据结构:神奇的B树实现解析(有图有代码有真相!!!)》

《数据结构:神奇的B树实现解析(有图有代码有真相!!!)》


《数据结构:神奇的B树实现解析(有图有代码有真相!!!)》


#pragma once
#include <iostream>
#include <stdlib.h>

using namespace std;

template<class K, int M>
struct BTreeNode
{
	typedef BTreeNode<K, M> Node;
	K _keys[M];//多给一个位置是为了先插入方便分裂
	Node* _sub[M+1];
	Node* _parent;
	size_t _size;//记录关键字的个数
	BTreeNode()
		:_parent(NULL)
	    ,_size(0)
	{
		for(size_t i = 0; i < M; i++)
		{
			_keys[i] = K();
			_sub[i] = 0;
		}
		_sub[M] = 0;
	}
};


template<class K, int M>
class BTree
{
	typedef BTreeNode<K, M> Node;
public:
	BTree()
		:_pRoot(NULL)
	{}
	void Inorder()
	{
		_Inorder(_pRoot);
	}
	~BTree()
	{
		_Destroy(_pRoot);
	}

	bool Insert(const K& key)
	{
		if(NULL == _pRoot)
		{
			_pRoot = new Node();
			_pRoot->_keys[0] = key;
			_pRoot->_size++;
			return true;
		}
		pair<Node*, size_t>	temp = _Find(key);
		if(temp.second != -1)
		{
			return false;
		}
		Node* cur = temp.first;
		Node* sub = NULL;
		K newKey = key;
		while(1)
		{
			_InsertKey(cur, newKey, sub);
			if(cur->_size < M)
			{
				return true;
			}
			while(cur->_size >= M)
			{
				size_t mid = cur->_size / 2;
				Node* NewNode = new Node;
				for(size_t i = mid+1; i < cur->_size; i++)
				{
					int j = 0; //新节点的下标
					NewNode->_keys[j] = cur->_keys[i];
					NewNode->_size++;
					cur->_keys[i] = K();//复制之后,对应的原位置key置为初始值。
					j++;
				}
				int j = 0;
				for(size_t i = mid+1; i < cur->_size+1; i++)
				{
					NewNode->_sub[j] = cur->_sub[i];
					if(NewNode->_sub[j])
						NewNode->_sub[j]->_parent = NewNode;
					j++;
					cur->_sub[i] = NULL;
				}

				if(cur == _pRoot)
				{
					Node* temp = new Node();
					temp->_keys[0] = cur->_keys[mid];
					cur->_keys[mid] = K();
					cur->_size = mid;
					temp->_size++;
					temp->_sub[0] = cur;
					cur->_parent = temp;
					temp->_sub[1] = NewNode;
					NewNode->_parent = temp;
					_pRoot = temp;

					return true;
				}

				newKey = cur->_keys[mid];
				cur->_keys[mid] = K();
				cur->_size = mid;
				sub = NewNode;
			}
			cur = cur->_parent;

		}

	}

protected:
	pair<Node*, size_t> _Find(const K& key)
	{
		Node* cur = _pRoot;
		Node* parent = NULL;
		while(cur)
		{
			size_t i = 0;
			while(i < cur->_size)
			{
				if(cur->_keys[i] < key)
					i++;
				else if(cur->_keys[i] > key)
					break;
				else
					return pair<Node*, size_t>(cur, i);
			}
			parent = cur;
			cur = cur->_sub[i];
		}
		return pair<Node*, size_t>(parent, -1);
	}

	void _InsertKey(Node* cur,const K& Key,Node* sub)
	{
		int i = cur->_size-1;
		while(i >= 0)
		{
			if(cur->_keys[i] > Key)
			{
				//移动关键字位置
				cur->_keys[i+1] = cur->_keys[i];
				//移动子树的位置
				cur->_sub[i+2] = cur->_sub[i+1];
				i--;
			}
			else
				break;
		}
		cur->_keys[i+1] = Key;
		cur->_sub[i+2] = sub;
		if(sub)
			sub->_parent = cur;

		cur->_size++;
	}

	void _Inorder(Node* _pRoot)
	{
		if(NULL == _pRoot)
			return;
		size_t i = 0;
		for(; i < _pRoot->_size; i++)
		{
			_Inorder(_pRoot->_sub[i]);
			cout<<_pRoot->_keys[i]<<" ";
		}
		_Inorder(_pRoot->_sub[i]);
	}

	void _Destroy(Node* _pRoot)
	{
		if(NULL == _pRoot)
			return;
		size_t i = 0;
		for(; i < _pRoot->_size; i++)
		{
			_Destroy(_pRoot->_sub[i]);
			delete _pRoot->_sub[i];
		}
		_Destroy(_pRoot->_sub[i]);
		delete _pRoot->_sub[i];

	}


private:
	Node* _pRoot;
};

void test()
{
	BTree<int, 3> bt;
	int array[] = {53, 75, 139, 49, 145, 36, 101};
	for(int i = 0; i < sizeof(array)/sizeof(array[0]); i++)
	{
		bt.Insert(array[i]);
	}
	bt.Inorder();
}


    原文作者:B树
    原文地址: https://blog.csdn.net/Sharp_UP/article/details/72872437
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞