【資料結構】平衡搜尋樹之---B樹的演算法實現
阿新 • • 發佈:2018-12-25
#include<iostream> using namespace std; #ifndef __BTREE_H__ #define __BTREE_H__ template<class K,int M=3>//設為三階B樹(每個陣列三個關鍵字) struct BNode { BNode<K,M>* _parent; size_t _size;//元素個數 K keys[M];//由於subs多了一個長度 BNode<K,M> *subs[M+1];//為了使插入元素分裂時先講該數放進陣列中再調整而又不越界 BNode() :_parent(NULL) ,_size(0) { for (int i = 0; i <= M + 1; i++) { subs[i] = NULL;//指標陣列每個元素都為空指標,key不初始化,sub初始化為空指標 } } }; template<class K,class V> struct Pair { K _first; V _second; Pair(const K& key=K(),const V& value=V()) :_first(key) , _second(value) {} }; template<class K,int M=3> class BTree { typedef BNode<K,M> Node; public: BTree() :_root(NULL) {} Pair<Node*,int> Find(const K& key) { if (_root == NULL) return Pair<Node*,int>(NULL,-1); //思路:根據元素的大小以及遍歷每個陣列的關鍵字判斷要走哪一條支路,再逐層逐層查詢 Node* cur = _root; Node* parent = NULL; while (cur) { int index = 0; while (index < cur->_size) { if (cur->keys[index] > key) { break; } else if (cur->keys[index] < key) { index++; } else { return Pair<Node*, int>(parent, index); } } parent = cur; cur = cur->subs[index]; } return Pair<Node*, int>(parent, -1); //找完也沒找到,為了使得該情況下方便插入節點,因此返回parent,插入節點插在parent上 } bool Insert(const K& key) { //思路:若無結點,插入根節點;若有節點,找到合適位置插入在根節點上,如果此時插上該節點後 //元素個數_size=M,則分裂,向上調整中位數,若調整後仍然是這樣,則繼續調整,直到不滿足。 if (_root == NULL) { _root = new Node; _root->keys[0] = key; _root->subs[0] = NULL; _root->_parent = NULL; _root->_size++; return true; } //若有該節點了,則不插入重複節點!!! if (Find(key)._second != -1)//不重複 { return false; } Node* cur = Find(key)._first;//!!!根據查詢到的位置直接插,避免程式碼冗餘 Node* sub = NULL; int insertKey = key; while (1) { _Insert(cur, sub, insertKey);//先將該元素key插入,放在該陣列的合適位置 if (cur->_size < M)//插入後,無需分裂 { return true; } //需要分裂 int index = 0; Node* tmp = new Node; int mid = (cur->_size-1) / 2; //拷貝key值 for (int i = mid + 1; i < cur->_size; i++) { tmp->keys[index++] = cur->keys[i]; tmp->_size++; } //拷貝關鍵字的下標 for (int i = mid + 1; i <= cur->_size; i++) { tmp->subs[index++] = cur->subs[i]; if (cur->subs[i])//有子鏈,鏈上 { cur->subs[i]->_parent = tmp; } } cur->_size = (cur->_size - 1) / 2;//更新cur陣列元素個數 if (cur->_parent == NULL) { //分兩條支路,左支路為cur,右支路為tmp鏈上 _root = new Node; _root->keys[0] = cur->keys[mid]; _root->subs[0] = cur; _root->subs[1] = tmp; _root->_size++; cur->_parent = _root; tmp->_parent = _root; return true; } else { insertKey = cur->keys[mid];//該插入mid位置元素 sub = tmp;//子串便成為tmp cur = cur->_parent;//繼續調整 } } } protected: void _Insert(Node* cur, Node* sub,const K& key) { size_t index = cur->_size; while (index >= 0 && cur->keys[index]>key)//為便於key查到合適位置,先將元素往後移動1個長度到合適位置 { cur->keys[index+1] = cur->keys[index]; cur->subs[index + 1] = cur->subs[index];//下標也要更新 index--; } cur->keys[index+1] = key; cur->subs[index + 2] = sub; if (sub) { sub->_parent = cur; } cur->_size++; } private: Node* _root; }; #endif //__BTREE_H__
測試程式碼:
#define _CRT_SECURE_NO_WARNINGS 1 #include "BTree.h" void BTreeTest() { BTree<int,3> btree; int a[] = { 53, 75, 139, 49, 145, 36, 101 }; for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++) { btree.Insert(a[i]); } btree.Find(5); } int main() { BTreeTest(); system("pause"); return 0; }