适用于外查找的平衡树——B树

来源:互联网 发布:分手炮内射 知乎 编辑:程序博客网 时间:2024/05/20 16:41

什么是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 oncetemplate<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 < keybreak;}}cur->_key[end+1] = key;cur->_subs[end+2] = sub;if (sub){//如果孩子存在sub->_parent = cur;}cur->_size++;}protected:Node* _root;};</span></strong>


0 0