什么是B树:
1970年,R.Bayer和E.mccreight提出了一种适用于外查找的树,它是一种平衡的多叉树,称为B树(或B-树、B_树)。在B-树中查找给定关键字的方法是,首先把根结点取来,在根结点所包含的关键字K1,…,kj查找给定的关键字(可用顺序查找或二分查找法),若找到等于给定值的关键字,则查找成功;否则,一定可以确定要查的关键字在某个Ki或Ki+1之间,于是取Pi所指的结点继续查找,直到找到,或指针Pi为空时查找失败。
图解B树的插入和分裂:
下面是关于B树的代码,以及涉及到的遍历B树的面试题
“test.cpp”
#define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> using namespace std; #include "BTree.h" void Test1() { BTree<int,3> bt; bt.Insert(20); bt.Insert(30); bt.Insert(10); } void Teat2() { BTree<int,3> bt; int arr[] = {53,75,139,49,145,36,101}; int size = sizeof(arr)/sizeof(arr[0]); for (size_t i = 0;i < size;i++) { bt.Insert(arr[i]); } bt.InOrder(); } int main() { //Test1(); Teat2(); system("pause"); return 0; }
"BTree.h"
<strong><span style="font-size:18px;">#pragma once template<class K,int M> struct BTreeNode { K _key[M];//多给了一个位置是为了方便处理分裂 BTreeNode<K,M>* _subs[M+1];//多给了一个位置是为了方便处理分裂 BTreeNode<K,M>* _parent; size_t _size;//存了几个关键字 //构造函数 BTreeNode() :_parent(NULL) ,_size(0) { for (size_t i = 0;i < M;i++) { _key[i] = K(); _subs[i] = NULL; } _subs[M] = NULL; } }; template<class K,int M> class BTree { typedef BTreeNode<K,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; for (i = 0;i < cur->_size;) { if (cur->_key[i] == key) { return pair<Node*,int>(cur,i); } else if (cur->_key[i] > key) { break; } else { i++; } } parent = cur; cur = cur->_subs[i]; } return pair<Node*,int>(parent,-1);//_root == NULL 的情况下返回 //找不到的情况下返回 } bool Insert(const K& key) { //第一个数据插入的情况 if (_root == NULL) { _root = new Node; _root->_key[0] = key; _root->_size = 1; return true; } pair<Node*,int> ret = Find(key); if (ret.second != -1) { //表明key值已经存在,则无需插入,错误返回 return false; } Node* cur = ret.first; K newkey = key; Node* sub = NULL; while (1) { InsertKey(cur,newkey,sub); if (cur->_size < M) { return true; } //分裂 int div = M / 2; Node* tmp = new Node;//先创建一个新的结点 int index = 0; size_t i = 0; for (i = div + 1;i <cur->_size;i++) { //拷贝右半区间的数据到新结点 tmp->_key[index++] = cur->_key[i]; tmp->_size++; cur->_key[i] = K(); } index = 0; for (i = div+1;i<cur->_size;i++) { //拷贝右半区间的孩子结点到新结点 tmp->_subs[index++] = cur->_subs[i]; if (cur->_subs[i]) { cur->_subs[i]->_parent = tmp; } } cur->_size = cur->_size - tmp->_size - 1;//中位数往上提 if (cur->_parent == NULL) { _root = new Node; _root->_key[0] = cur->_key[div]; cur->_key[div] = K(); _root->_subs[0] = cur; cur->_parent = _root; _root->_subs[1] = tmp; tmp->_parent = _root; _root->_size = 1; return true; } else { newkey = cur->_key[div]; cur->_key[div] = K(); cur = cur->_parent; sub = tmp; } } return true;//只要能跳出while(1)的死循环,就一定有返回值的了, //这里的返回值是没有意义的 } void InOrder() { _InOrder(_root); cout<<endl; } private: void _InOrder(Node* root) { if (root == NULL) { return; } size_t i = 0; for (i = 0;i < root->_size;i++) { _InOrder(root->_subs[i]); cout<<root->_key[i]<<" "; } _InOrder(root->_subs[i]); } void InsertKey(Node* cur,const K& key,Node* sub) { int end = cur->_size-1;//让end指向数据的最后一个位置 while (end >= 0) { if (cur->_key[end] > key) { cur->_key[end+1] = cur->_key[end]; cur->_subs[end+2] = cur->_subs[end+1]; end--; } else { //end->_key < key break; } } cur->_key[end+1] = key; cur->_subs[end+2] = sub; if (sub) { //如果孩子存在 sub->_parent = cur; } cur->_size++; } protected: Node* _root; };</span></strong>