1. 程式人生 > >B-樹 構建

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】之間

  5.所有的葉子節點都在同一層

ps:以上來源資料


    關鍵字比孩子的個數永遠少一個,如下圖。且可以將多叉樹在每個節點處抽象為關鍵字個二叉樹,如下圖關鍵字為  40  50  ,可看做兩個共用一個孩子的二叉樹,40 的右孩子與 50 的左孩子共用。這樣可幫助理解結構。

   節點

        構建B-樹,先分析節點的組成。每個節點都包含一個關鍵字陣列、一個指向孩子上的指標陣列,一個指向下一節點的指標組成,為了方便後續的功能實現,再新增一個指向父親節點的指標。程式碼如下:


template <class K,class V, size_t M = 3>
struct BTreeNode
{
BTreeNode(const pair<K, V>& kv = pair<K, V>())
{
_parent = NULL;
_size = 0;
for (size_t i = 0; i < M + 1; ++i)
{
_sub[i] = NULL;
}
}
pair<K, V> _kvs[M]; //關鍵字最多為M-1 ,此處設為M,方便插入,以防越界
BTreeNode<K, V>* _sub[M + 1];//孩子數比關鍵字大一個
BTreeNode<K, V>* _parent;
size_t _size;
};

      B-樹在一個_root的根節點開始滿足上面的性質進行的操作。

template <class K, class V, size_t M = 3>
class BTree
{
typedef BTreeNode<K, V> Node;
public:
BTree()
:_root(NULL)
{}
//各種功能實現
protected:
Node* _root;
};

功能

 1.查詢Find

pair<Node*, int> Find(const K &key)
{
Node* cur = _root;
Node* parent = NULL;
while (cur)
{
cur->_parent = parent;
size_t i = 0;
for (; i < cur->_size; )
{
if (cur->_kvs[i].first > key)
{
break;
}
else if (cur->_kvs[i].first == key)
{
return make_pair(cur, i);
}
else
{
++i;
}
}
parent = cur;
cur = cur->_sub[i];
}
return make_pair(parent, -1);
}

        2.插入 Insert()

bool Insert(const pair<K, V>&kv)
{


if (_root == NULL)
{
_root = new Node;
_root->_kvs[0] = kv;
_root->_size++;
return true;
}
else
{
pair<Node*, int> ret = Find(kv.first);




if (ret.second != -1)
{
return false;
}
else
{
Node* cur = ret.first;
pair<K, V> newKV = kv;
Node* sub = NULL;
while (1)
{
_InsertKV(cur, newKV, sub);




if (cur->_size < M)
return true;


size_t mid = M / 2;
Node* tmp = new Node;
size_t j = 0;
size_t i = mid + 1;
for (; i < cur->_size; ++i)
{
tmp->_kvs[j] = cur->_kvs[i];
cur->_kvs[i] = pair<K, V>();
tmp->_sub[j] = cur->_sub[i];
if (cur->_sub[i])
cur->_sub[i]->_parent = tmp;
tmp->_size++;
++j;
}


tmp->_sub[j] = cur->_sub[i];
if (cur->_sub[i])
cur->_sub[i]->_parent = tmp;
cur->_size = cur->_size - tmp->_size-1;
if (cur->_parent == NULL)
{
_root = new Node;
_root->_kvs[0] = cur->_kvs[mid];
cur->_kvs[mid] = pair<K, V>();
_root->_size = 1;


_root->_sub[0] = cur;
_root->_sub[1] = tmp;
cur->_parent = _root;
return true;
}


else
{
newKV = cur->_kvs[mid];
sub = tmp;
cur->_kvs[mid] = pair<K, V>();
cur = cur->_parent;


}


}
}


}
}

void _InsertKV(Node* &cur, pair<K, V> &newKV, Node* &sub)
{

for (size_t i = 0; i < cur->_size; ++i)
{
if (newKV.first < cur->_kvs[i].first)
{
for (size_t j = cur->_size; j > i; --j)
{
cur->_kvs[j] = cur->_kvs[j - 1];
cur->_sub[j + 1] = cur->_sub[j];
}
cur->_kvs[i] = newKV;
cur->_sub[i + 1] = sub;
if (sub)
{
sub->_parent = cur;
}
cur->_size++;
return;
}
}
cur->_kvs[cur->_size] = newKV;
cur->_sub[cur->_size + 1] = sub;
if (sub)
{
sub->_parent = cur;
}
cur->_size++;
}

       3.排序 InOrder()

根據B-樹的特性,可以利用中序遍歷

void InOrder()
{
if (_root == NULL)
return;
_InOrder(_root);
cout << endl;
}

void _InOrder(Node* cur)
{
if (cur == NULL)
return;
size_t i = 0;
for (; i < cur->_size; ++i)
{
_InOrder(cur->_sub[i]);
cout << cur->_kvs[i].first<<" ";
}
_InOrder(cur->_sub[i]);
}