一、B树引入
二叉搜索树、平衡二叉树、红黑树都是动态查找树,典型的二叉搜索树结构,查找的时间复杂度和树的高度相关O(log2N)。
1)数据杂乱无章——-线性查找–O(n)
2)数据有序——-二分查找 —O(log 2 n) 最差退化成单支树—–线性结构
3)二叉搜索树、AVL树、红黑树 ——–O(log2 n)
数据一般保存在磁盘上,若数据量过大不能全部加载到内存,为了访问所有数据,使用如下搜索树结构保存数据:树的结点中保存权值和磁盘的地址
那如何加速对数据的访问速度呢?
提高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
#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(); }