溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

多路平衡樹(shù)—BTree(B樹(shù))

發(fā)布時(shí)間:2020-05-26 11:27:17 來(lái)源:網(wǎng)絡(luò) 閱讀:1924 作者:無(wú)心的執(zhí)著 欄目:編程語(yǔ)言

      B樹(shù)屬于多叉樹(shù),也稱多路平衡樹(shù)。有些地方也將B樹(shù)稱為'B-樹(shù)',這里‘-’不表示減號(hào)。


■B樹(shù)的主要性質(zhì)

              (1)根節(jié)點(diǎn)至少有兩個(gè)孩子。

              (2)每個(gè)非根節(jié)點(diǎn)為[[M/2], M]個(gè)孩子,這里[M/2]表示向上取整。

              (3)每個(gè)非根節(jié)點(diǎn)都有[[M/2], M-1]個(gè)關(guān)鍵字,并且以升序排列。

              (4)K[i]和k[i+1]之間的孩子節(jié)點(diǎn)的值介于k[i]與k[i+1]之間。(5)所有葉子節(jié)點(diǎn)都在同一層。



■下面是一個(gè)簡(jiǎn)單的3階B樹(shù):


多路平衡樹(shù)—BTree(B樹(shù))


     如果想給B樹(shù)中,插入一個(gè)關(guān)鍵字,并且關(guān)鍵字的數(shù)目超過(guò),且就需要對(duì)樹(shù)進(jìn)行調(diào)整。那就需要尋找關(guān)鍵字的中位數(shù),那怎樣快速的尋找關(guān)鍵字呢?


     ▲思路一:

            將所有的關(guān)鍵字進(jìn)行排序,然后將中位數(shù)尋找出來(lái)。

      ▲思路二:

              利用快速排序的思想,選一個(gè)key值,如果左邊個(gè)數(shù)等于右邊個(gè)數(shù),則中位數(shù)找到,如果沒(méi)有,就在個(gè)數(shù)多的一邊找出中間位置的關(guān)鍵字作為key值,直到key的左 = 右,則找到關(guān)鍵字,這樣的效率更高。




■下面是插入關(guān)鍵字示例:


多路平衡樹(shù)—BTree(B樹(shù))


■下面是具體的實(shí)現(xiàn)代碼:

#pragma once
//實(shí)現(xiàn)B樹(shù)(實(shí)際就是多叉樹(shù))

/*
性質(zhì):(1)根節(jié)點(diǎn)至少要2個(gè)節(jié)點(diǎn)
      (2)每個(gè)非根節(jié)點(diǎn)為[(M/2), M]個(gè)孩子
   (3)滿足左孩子值小于根節(jié)點(diǎn),右孩子值大于根節(jié)點(diǎn)
   (4)并且每個(gè)非根節(jié)點(diǎn)有[(M/2)-1, M-1]個(gè)關(guān)鍵字,并且以升序排列
   (5)key[i]和key[i+1]之間的孩子節(jié)點(diǎn)值介于key[i]和key[i+1]之間
   (6)所有節(jié)點(diǎn)都在同一層
*/

//實(shí)現(xiàn)k形式的結(jié)構(gòu)
//如果要實(shí)現(xiàn)K,V結(jié)構(gòu),就需要?jiǎng)?chuàng)建一個(gè)結(jié)構(gòu)體,包括K,V
template <class K, int M = 3>   //實(shí)現(xiàn)M為缺省的,值最好取計(jì)數(shù),能夠更加方便的求取中位數(shù)
struct BTreeNode
{
     K _keys[M];      //關(guān)鍵字的至多個(gè)數(shù),多預(yù)留一個(gè)位置是可以更加方便的求取中位數(shù)
     BTreeNode<K, M>* _subs[M + 1];      //孩子節(jié)點(diǎn)的最大數(shù)目
     BTreeNode<K, M>* _parent;    //指向父親節(jié)點(diǎn)
     size_t _size;     //數(shù)組中存在的有效關(guān)鍵字的個(gè)數(shù)
     
     BTreeNode()           //構(gòu)造B樹(shù)節(jié)點(diǎn)
          :_parent(NULL)
          , _size(0)
     {
          for (int i = 0; i <= M; ++i)
          {
               _subs[i] = NULL;
          }
     }
};

template <class K, class V>    //需要返回兩個(gè)參數(shù),使用結(jié)構(gòu)體
struct Pair
{
     K _first;
     V _second;
     
     Pair(const K& key = K(), const V& value = V())     //缺省參數(shù),會(huì)調(diào)用默認(rèn)構(gòu)造函數(shù)
          :_first(key)
          , _second(value)
     { }
};

template <class K, int M = 3>
class BTree
{
     typedef BTreeNode<K, M> Node;
public:
     BTree()          //無(wú)參構(gòu)造
          :_root(NULL)
     {}
     
     Pair<Node*, int>  Find(const K& key)      //查找
     {
          Node* parent = NULL;
          Node* cur = _root;
          while (cur)
          {
               int index = 0;
               while (index < cur->_size)     //在一個(gè)節(jié)點(diǎn)中找相同的關(guān)鍵字
               {
                    if (key == cur->_keys[index])
                    {
                         return Pair<Node*, int>(cur, index);
                    }
                    else if (key < cur->_keys[index])
                    {
                         break;
                    }
                    else
                    {
                         index++;
                    }
               }
               parent = cur;
               cur = cur->_subs[index];
          }
          return Pair<Node*, int>(parent, -1);
     }
     
     bool Insert(const K& key)     //插入節(jié)點(diǎn)
     {
          //沒(méi)有節(jié)點(diǎn)
          if (_root == NULL)
          {
               _root = new Node;
               _root->_keys[0] = key;
               _root->_size++;
               return true;
          }
          
          //判斷返回值
          Pair<Node*, int> cur = Find(key);
          if (cur._second != -1)
          {
               return false;
          }
          
          //在節(jié)點(diǎn)cur中插入key和sub
          Node* str = cur._first;
          K InsertKey = key;
          Node* sub = NULL;
          while (1)
          {
               _InsertKey(str, InsertKey, sub);    
               if (str->_size < M)    //插入后,節(jié)點(diǎn)中的數(shù)據(jù)個(gè)數(shù)沒(méi)有超過(guò)規(guī)定的
               {
                    return true;
               }
               //插入數(shù)據(jù)后,節(jié)點(diǎn)的數(shù)據(jù)個(gè)數(shù)大于規(guī)定的數(shù)據(jù)個(gè)數(shù),需要將節(jié)點(diǎn)進(jìn)行分裂
               int mid = (str->_size - 1) / 2;
               int index = 0;
               Node* tmp = new Node;
               
               //先拷貝key
               for (int i = mid + 1; i < str->_size; i++)
               {
                    tmp->_keys[index++] = str->_keys[i];
                    tmp->_size++;
               }
               
               //后拷貝sub
               for (int i = mid + 1; i < str->_size; i++)
               {
                    tmp->_subs[index + 1] = str->_subs[i];
                    if (str->_subs[i])
                    {
                         str->_subs[i]->_parent = tmp;
                    }
               }
               str->_size = (str->_size - 1) / 2;    //更改str的大小
               if (str->_parent == NULL)
               {
                    _root = new Node;
                    _root->_keys[0] = tmp->_keys[mid];
                    _root->_subs[0] = str;
                    _root->_subs[1] = tmp;
                    _root->_size = 1;
                    str->_parent = _root;
                    tmp->_parent = _root;
               }
               else
               {
                    InsertKey = str->_keys[mid];
                    sub = tmp;
                    str = str->_parent;
               }
          }
          return true;
     }
     
     void _InsertKey(Node* cur, const K& key, Node* sub)     //插入key值
     {
          int index = cur->_size - 1;
          while (index >= 0 && cur->_keys[index] > key)    //將后面的數(shù)據(jù)向后移一位
          {
               cur->_keys[index + 1] = cur->_keys[index];
               cur->_subs[index + 2] = cur->_subs[index + 1];
               --index;
          }
          cur->_keys[index + 1] = key;    //插入數(shù)據(jù)及其子節(jié)點(diǎn)
          cur->_subs[index + 2] = sub;
          if (sub)
               sub->_parent = cur;
          cur->_size++;
     }
     
     void InOrder()
     {
          _InOrder(_root);
     }
     
     void _InOrder(Node* root)
     {
          if (root == NULL)
          {
               return;
          }
          for (int i = 0; i < root->_size; i++)
          {
               cout << root->_keys[i] << " ";
               _InOrder(root->_subs[i]);
          }
     }
 
protected:
     Node* _root;
};

void Test()
{
     int a[] = { 53, 75, 139, 49, 145, 36, 101 };
     BTree<int, 1023> t;
     for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
     {
          t.Insert(a[i]);
     }
     t.InOrder();
}





向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI