B树的引入
二叉搜索树、平衡二叉树、红黑树都是动态查找树,查找的时间复杂度和树的高度相关 O(log2n).
数据杂乱无章——线性搜索 O(n)数字有序——二分查找 O(log2n) 最差退化成左单支树 O(n)二叉搜索树/AVL/红黑树——O(log2n)
缺陷:数据量大时,树的高度太高,效率下降。
如何解决?
1.提高I/O的时间2.降低树的高度——平衡多叉树。
B树定义
平衡的多叉树,称为B树(B-树)。
一棵M阶(M>2)的B树,是一个平衡的M路平衡搜索树,可以是空树或者满足以下性质:1.根节点至少有两个孩子。2.每个非根结点至少有M/2(上取整)个孩子,至多有M个孩子。3.每个分根结点至少有M/2-1(上取整)个孩子,至多有M个孩子。4.key[i]和key[i+1]之间的孩子结点的值介于key[i]、key[i+1]之间。5.所有的叶子结点都在同一层。图解
代码
#include <iostream> using namespace std; template<class K, size_t M> struct BTreeNode { typedef BTreeNode<K,M> Node; BTreeNode() :size(0) ,_pParent(NULL) {} K _keys[M]; //关键字集合 Node* _pSon[M+1];//孩子指针集合 size_t size; Node* _pParent; }; template<class K,size_t M> class BTree { typedef BTreeNode<K,M> Node; public: BTree() :_pRoot(NULL) {} bool Insert(const K&key) { if (_pRoot == NULL) //若树为空 { _pRoot = new Node(); _pRoot->_keys[0] = key; _pRoot->size++; _pRoot->_pSon[0] = NULL; _pRoot->_pSon[1] = NULL; return true; } //找插入位置 pair<Node*,int> s = Find(key); if (s.second != -1) //已经存在 return false; Node* pCur = s.first; Node* pSub = NULL; K key1 = key; while(true) { _Insertkey(pCur,key1,pSub); //插入key值 pSub是插入的结点的孩子,若是新插入的,则pSub的值赋为NULL
//若是往上调整的,则需要调整孩子 if (pCur->size <M) //无需调整 return true; else { size_t mid = pCur->size/2; //分裂取中 Node* pNew = new Node(); size_t count = 0; size_t idx ; for( idx = mid+1;idx<pCur->size;) { pNew->_keys[count] = pCur->_keys[idx]; pNew->_pSon[count++] = pCur->_pSon[idx++]; } pNew->_pSon[count] = pCur->_pSon[idx]; pCur->size = pCur->size - mid - 1; pNew->size = count; if (pCur == _pRoot) //若原结点是根节点 { _pRoot = new Node(); _pRoot->_keys[0] = pCur->_keys[mid]; _pRoot->_pSon[0] = pCur; pCur->_pParent = _pRoot; _pRoot->_pSon[1] = pNew; pNew->_pParent = _pRoot; _pRoot->size++; return true; } pSub = pNew; //更新孩子指针 key1 = pCur->_keys[mid]; //更新要插入的值 pCur = pCur->_pParent; 向上调整 } } } pair<Node*,int> Find(const K& key) //若查找失败,则返回 NULL和-1 { Node * pCur = _pRoot; Node* pParent = NULL; size_t idx = 0; while (pCur) { idx = 0; while (idx < pCur->size) { if (pCur->_keys[idx]<key ) idx++; else if (pCur->_keys[idx]>key) break; else return make_pair(pCur,idx); } if (idx == pCur->size&&pCur->_pSon[idx] == NULL) { return make_pair(pCur,-1); } else { pParent = pCur; pCur = pCur->_pSon[idx]; } } return make_pair(pParent,-1); } void InOrder() { _InOrder(_pRoot); } private: void _InOrder(Node* &pRoot) { if (pRoot== NULL) return; size_t idx; for(idx =0 ;idx<pRoot->size;++idx) { _InOrder(pRoot->_pSon[idx]); cout<<pRoot->_keys[idx]<<" "; } _InOrder(pRoot->_pSon[idx]); } void _Insertkey(Node* &pCur,const K& key,Node* pSub) { size_t end = pCur->size -1; while(end >= 0) { if (pCur->_keys[end] >key) //后搬 { pCur->_keys[end+1]= pCur->_keys[end]; pCur->_pSon[end+2] = pCur->_pSon[end+1]; --end; } else { pCur->_keys[end+1] = key; pCur->_pSon[end+2] = pSub; ++pCur->size; return; } } pCur->_keys[0] = key; pCur->_pSon[0] = pSub; ++pCur->size; } private: Node* _pRoot; };