平衡搜索树-BTree
2017-11-20 17:33
381 查看
B树是一种适合外查找的树,是一种平衡 的多叉树。
一棵M阶(M>2)的B树,是一棵平衡的M路平衡搜索树,可以是空树或者满足一下性质:
1。根节点至少有两个孩子
2。每个非根节点有[M/2,M]个孩子
3。每个非根节点有[M/2-1,M-1]个关键字,并且以升序排列
4。每个节点孩子的数量比关键字的数量多一个。
5。 key[i]和key[i+1]之间的孩子节点的值介于key[i]、key[i+1]之间
6。 所有的叶子节点都在同一层
下面用代码来实现一下B树
B+树
B+树是对B树的一种变形树,它与B树的差异在于:
有k个子结点的结点必然有k个关键码;
非叶结点仅具有索引作用,跟记录有关的信息均存放在叶结点中。
树的所有叶结点构成一个有序链表,可以按照关键码排序的次序遍历全部记录。
B+树更适合文件索引系统
B*树
B*树定义了非叶子结点关键字个数至少为(2/3)*M,即块的最低使用率为2/3
(代替B+树的1/2);
B+树的分裂:当一个结点满时,分配一个新的结点,并将原结点中1/2的数据
复制到新结点,最后在父结点中增加新结点的指针;B+树的分裂只影响原结点和父
结点,而不会影响兄弟结点,所以它不需要指向兄弟的指针;
B*树的分裂:当一个结点满时,如果它的下一个兄弟结点未满,那么将一部分
数据移到兄弟结点中,再在原结点插入关键字,最后修改父结点中兄弟结点的关键字
(因为兄弟结点的关键字范围改变了);如果兄弟也满了,则在原结点与兄弟结点之
间增加新结点,并各复制1/3的数据到新结点,最后在父结点增加新结点的指针;
所以,B*树分配新结点的概率比B+树要低,空间使用率更高;
一棵M阶(M>2)的B树,是一棵平衡的M路平衡搜索树,可以是空树或者满足一下性质:
1。根节点至少有两个孩子
2。每个非根节点有[M/2,M]个孩子
3。每个非根节点有[M/2-1,M-1]个关键字,并且以升序排列
4。每个节点孩子的数量比关键字的数量多一个。
5。 key[i]和key[i+1]之间的孩子节点的值介于key[i]、key[i+1]之间
6。 所有的叶子节点都在同一层
下面用代码来实现一下B树
#pragma once template<class K, class V, size_t M> struct BTreeNode { pair<K, V> _kvs[M]; // 多开一个空间,方便分裂 BTreeNode<K, V, M>* _subs[M+1]; BTreeNode<K, V, M>* _parent; size_t _size; // 关键字的数量 BTreeNode() :_parent(NULL) ,_size(0) { for (size_t i = 0; i < M+1; ++i) { _subs[i] = NULL; } } }; template<class K, class V, size_t M> class BTree { typedef BTreeNode<K, V, M> Node; public: BTree() :_root(NULL) {} pair<Node*, int> Find(const K& key) { Node* parent = NULL; Node* cur = _root; while (cur) { size_t i = 0; while(i < cur->_size) { if (cur->_kvs[i].first > key) // 在[i]的左树 break; else if (cur->_kvs[i].first < key) // 在后面 ++i; else return make_pair(cur, i); } parent = cur; cur = cur->_subs[i]; } return make_pair(parent, -1); } bool Insert(const pair<K, V>& kv) { if (_root == NULL) { _root = new Node; _root->_kvs[0] = kv; _root->_size = 1; return true; } pair<Node*, int> ret = Find(kv.first); if (ret.second >= 0) { return false; } Node* cur = ret.first; pair<K, V> newKV = kv; Node* sub = NULL; // 往cur插入newKV, sub while (1) { InsertKV(cur, newKV, sub); if (cur->_size < M) { return true; } else { // 分裂 Node* newNode = DivideNode(cur); pair<K, V> midKV = cur->_kvs[cur->_size/2]; cur->_size -= (newNode->_size+1); // 1.根节点分裂 if (cur == _root) { _root = new Node; _root->_kvs[0] = midKV; _root->_size = 1; _root->_subs[0] = cur; _root->_subs[1] = newNode; cur->_parent = _root; newNode->_parent = _root; return true; } else { sub = newNode; newKV = midKV; cur = cur->_parent; } } } } Node* DivideNode(Node* cur) { Node* newNode = new Node; int mid = cur->_size/2; size_t j = 0; size_t i = mid+1; for (; i < cur->_size; ++i) { newNode->_kvs[j] = cur->_kvs[i]; newNode->_subs[j] = cur->_subs[i]; if(newNode->_subs[j]) newNode->_subs[j]->_parent = newNode; newNode->_size++; j++; } newNode->_subs[j] = cur->_subs[i]; if(newNode->_subs[j]) newNode->_subs[j]->_parent = newNode; return newNode; } void InsertKV(Node* cur, const pair<K, V>& kv, Node* sub) { int end = cur->_size-1; while (end >= 0) { if (cur->_kvs[end].first > kv.first) { cur->_kvs[end+1] = cur->_kvs[end]; cur->_subs[end+2] = cur->_subs[end+1]; --end; } else { break; } } cur->_kvs[end+1] = kv; cur->_subs[end+2] = sub; if(sub) sub->_parent = cur; cur->_size++; } void InOrder() { _InOrder(_root); cout<<endl; } void _InOrder(Node* root) { if (root == NULL) return; Node* cur = root; size_t i = 0; for (; i < cur->_size; ++i) { _InOrder(cur->_subs[i]); cout<<cur->_kvs[i].first< 4000 <" "; } _InOrder(cur->_subs[i]); } private: Node* _root; }; void TestBTree() { BTree<int, int, 3> t; int a[] = {53, 75, 139, 49, 145, 36, 101}; for (size_t i = 0; i < sizeof(a)/sizeof(a[0]); ++i) { t.Insert(make_pair(a[i], i)); } t.InOrder(); } template<class K, size_t M> struct BPTreeNonLeafNode { K _keys[M]; void* _subs[M]; BPTreeNonLeafNode<K, M>* _parent; size_t _size; }; template<class K, class V, size_t M> struct BPTreeLeafNode { pair<K, V> kvs[M]; BPTreeLeafNode<K, V>* _next; BPTreeNonLeafNode<K, M>* _parent; size_t _size; }; template<class K, class V, size_t M> class BPTree { typedef BPTreeLeafNode<K, V, M> LeafNode; typedef BPTreeLeafNode<K, M> NonLeafNode; private: NonLeafNode* _root; LeafNode* _head; };
B+树
B+树是对B树的一种变形树,它与B树的差异在于:
有k个子结点的结点必然有k个关键码;
非叶结点仅具有索引作用,跟记录有关的信息均存放在叶结点中。
树的所有叶结点构成一个有序链表,可以按照关键码排序的次序遍历全部记录。
B+树更适合文件索引系统
B*树
B*树定义了非叶子结点关键字个数至少为(2/3)*M,即块的最低使用率为2/3
(代替B+树的1/2);
B+树的分裂:当一个结点满时,分配一个新的结点,并将原结点中1/2的数据
复制到新结点,最后在父结点中增加新结点的指针;B+树的分裂只影响原结点和父
结点,而不会影响兄弟结点,所以它不需要指向兄弟的指针;
B*树的分裂:当一个结点满时,如果它的下一个兄弟结点未满,那么将一部分
数据移到兄弟结点中,再在原结点插入关键字,最后修改父结点中兄弟结点的关键字
(因为兄弟结点的关键字范围改变了);如果兄弟也满了,则在原结点与兄弟结点之
间增加新结点,并各复制1/3的数据到新结点,最后在父结点增加新结点的指针;
所以,B*树分配新结点的概率比B+树要低,空间使用率更高;
相关文章推荐
- 平衡搜索树--红黑树 RBTree
- 二叉树问题---通过有序数组生成平衡搜索二叉树
- 高效的平衡搜索树——红黑树
- 【算法导论】 第十课 平衡搜索树
- java平衡搜索树AVL实现
- 平衡搜索树—AVLTree
- 【平衡搜索树】AVL树
- AVL平衡搜索树
- 数据结构-平衡搜索二叉树(AVL树)
- Elasticsearch学习之深入搜索六 --- 平衡搜索结果的精准率和召回率
- [LeetCode] 从排序的单链表到平衡搜索二叉树
- 平衡搜索树之红黑树(图片格式)
- 平衡搜索树的左单旋、右单旋、左右双旋、右左双旋
- 平衡搜索二叉树的python实现
- 搜索:平衡2-3-4树和(左倾)红黑树
- 平衡搜索树-AVL树
- 平衡搜索树—AVLTree
- 【数据结构】中平衡搜索树的旋转方式解析
- 【数据结构】平衡搜索树之---B树的算法实现
- 平衡搜索树之AVLTree