【数据结构】浅析B树
来源:互联网 发布:淘宝注销账号怎么注销 编辑:程序博客网 时间:2024/05/01 23:37
一、B树的概念
B树,概括来说是一个节点可以拥有多于2个子节点的平衡多叉树。
特点:
1> 根节点至少有两个子节点
2>每个非跟节点节点有(M/2)-1至M-1个key
3>每个非根节点有[M/2 ,M]个孩子
4>key[i]和key[i+1]之间的孩子节点的值介于key[i]、key[i+1]之间
5> 所有的叶子节点都在同一层
二、B树的应用
由于增删查改的效率十分高(时间复杂度log M-1为底N的对数的样子),B树普遍应用于数据库和文件系统。一般会将M定义的非常大,这样B树的高度就很低,每一个节点中可以使用二分查找,所以B树效率高。缺点就是比较耗内存。
三、实现一个B树
1.节点内容
根据B树的特点,一个节点应该包含一个大小为M-1的key数组,但是考虑到B树在插入的时候需要先插入节点然后在进行分裂,所以key数组给M大的空间。其次,应该包含一个节点指针类型的数组,存储指向孩子的指针,大小应为M+1。还有,一个指向父节点的指针,一个表示当前结点key值实际数量的size。
2.节点插入
1>空树时,直接调用节点的构造函数,new一个root。
2>非空时,先查找树,若已经存在要插入的关键码,则插入失败。若不存在,让Find()函数返回插入位置的指针。那么,Find不仅要返回key值是否在树内(bool),还要返回要插入节点的位置(Node*)。所以,我们使用库里存在的一个类型pair,它可以带回两个返回值。
3>接下来,把key值插入Find返回的位置。
4>检测插入后key值的个数是否超过M-1,若没有,则插入成功,若超过,则需要分裂。根据B树的特点,可以知道,插入的位置只能是叶子节点。
分裂是怎么一回事呢?看下图
分裂是插入的难点,理解了分裂,插入就没什么问题了。
3.代码实现
#include<iostream>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{public:typedef BTreeNode<K, M> Node;BTree():_root(NULL){}void InOrder(){_InOrder(_root);}~BTree(){_Destory(_root);}bool Insert(const K& key){if (NULL == _root){_root = new Node();_root->_keys[0] = key;_root->_size++;return true;}pair<Node*, size_t> tmp = _Find(key);if (tmp.second != -1) //已经存在关键值为key,则不能插入{return false;}Node* cur = tmp.first;Node* sub = NULL;K newkey = key;while (1){_Insertkey(cur,newkey,sub); //先将key放进要插的节点//判断结点的关键字数目是否符合标准。if (cur->_size < M) //该节点上插入后关键字数目正常return true;//数目超过规定值需要进行分裂while (cur->_size >= M){size_t mid = cur->_size / 2;//1.分裂出新的结点Node* NewNode = new Node;for (size_t i = mid+1; i < cur->_size; i++)//mid之后的key值给新结点{int j = 0;NewNode->_keys[j] = cur->_keys[i];NewNode->_size++;//cur->_size--; //注意此处先不要哦改动cur的size,否则会影响下一个循环cur->_keys[i] = K(); //赋给新结点后cur对应的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 == _root) //创建出新的根节点{Node* tmp = new Node();tmp->_keys[0] = cur->_keys[mid];cur->_keys[mid] = K();cur->_size=mid;tmp->_size++;tmp->_sub[0] = cur;cur->_parent = tmp;tmp->_sub[1] = NewNode;NewNode->_parent = tmp;_root = tmp;return true;}newkey = cur->_keys[mid];cur->_keys[mid] = K();cur->_size = mid; sub = NewNode;}cur = cur->_parent;}}protected:void _Destory(Node* root){if (NULL == root)return;size_t i = 0;for (; i < root->_size; i++){_Destory(root->_sub[i]);delete root->_sub[i];}_Destory(root->_sub[i]);delete root->_sub[i];}void _InOrder(Node* root){if (NULL == root)return;size_t i = 0;for (; i < root->_size; i++){_InOrder(root->_sub[i]);cout << root->_keys[i]<<" ";}_InOrder(root->_sub[i]);}pair<Node*,size_t> _Find(const K& key){Node* cur = _root;Node* parent = NULL;while (cur){size_t i = 0;while (i< cur->_size) //找当前结点的key{if (cur->_keys[i] < key)i++;else if (cur->_keys[i]>key)//cur = cur->_sub[i];break;else //找到了和传入key相等的关键字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--;}elsebreak;}//i记录着要插入位置的前一个cur->_keys[i + 1] = key;cur->_sub[i + 2] = sub;if (sub)sub->_parent = cur;cur->_size++;}private:Node* _root;};void TestBTree(){BTree<int, 3> bt;int a[] = { 53, 75, 139, 49, 145, 36, 101 };for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++){bt.Insert(a[i]);}bt.InOrder();}
- 【数据结构】浅析B树
- 浅析B-树
- 浅析数据结构与算法10--平衡查找树之B树
- 【数据结构】B树/B+树
- 数据结构--B 树、B+ 树、B* 树
- 数据结构:B树&B+树&B*树
- dump浅析B树索引
- 数据结构--B树
- 经典数据结构B+树
- 数据结构B-树
- 【数据结构】B树_BTree
- 数据结构B树
- 数据结构-B树实现
- 数据结构之B树
- B+树数据结构
- 高级数据结构B树
- 数据结构-----------B树
- 数据结构之B-树
- CDH集群调优:内存、Vcores和DRF
- Java学习笔记-高级for循环
- 01UI-day2-151226
- Android IPC :通过Localsocket完成
- 【NOIP】NOIP考纲总结+NOIP考前经验谈
- 【数据结构】浅析B树
- 对数组名与指针的认识
- 第十二周项目1-图基本算法库
- axis2+spring集成
- opencv(九)之轨迹条条创建和使用createTrackbar
- js导出EXCLE
- 01UI-day3-151228
- readyState的五种状态
- 图邻接表有向表代码简洁实现