T:B數的表示及其基本操作的實現(C++)
阿新 • • 發佈:2018-12-24
習題內容:
1.掌握B樹的存貯結構。
2.實現B樹中關鍵字值的插入及刪除操作。
B樹的定義:
B樹也稱B-樹,它是一顆多路平衡查詢樹。我們描述一顆B樹時需要指定它的階數,階數表示了一個結點最多有多少個孩子結點,一般用字母M表示階數。當M取2時,就是我們常見的二叉搜尋樹。
一顆M階的B樹定義如下:
1)每個結點最多有M-1個關鍵字。
2)根結點最少可以只有1個關鍵字。
3)非根結點至少有Math.ceil(M / 2)-1個關鍵字。
4)每個結點中的關鍵字都按照從小到大的順序排列,每個關鍵字的左子樹中的所有關鍵字都小於它,而右子樹中的所有關鍵字都大於它。
5)所有葉子結點都位於同一層,或者說根結點到每個葉子結點的長度都相同。
程式碼實現:
/*測試環境:VS2017*/ #include <iostream> #include<cstdio> #include<cstring> using namespace std; typedef struct _BTreeNode { int key_count; int* key; bool leaf; _BTreeNode** child; }BTreeNode, *PBTreeNode; class BTree { private: PBTreeNode root; int t;//B樹的度,樹的階數為2t***m=2t,t=m/2 public: BTree(int m):root(NULL), t(m){}//構造 ~BTree(){DeleteTree(root);delete root;}//析構 //基本操作:插入,刪除,列印,查詢 void Insert(int key); void Delete(int key) { DeleteNonHalf(root, key); } void Display() { Print(root); } bool Search(int key); private: PBTreeNode SearchBT(PBTreeNode pNode, int key); PBTreeNode AllocateNode();//劃分節點,初始化 PBTreeNode UnionChild(PBTreeNode pParent, PBTreeNode pCLeft, PBTreeNode pCRight, int index);//結合兄弟節點 int Max(PBTreeNode pNode); int Min(PBTreeNode pNode); void DeleteNonHalf(PBTreeNode pNode, int key);//刪除不足的節點 void InsertNonfull(PBTreeNode pNode, int key);//插入未滿的節點 void SplitChild(PBTreeNode pParent, int index, PBTreeNode pChild);//劃分子節點 void DeallocateNode(PBTreeNode pNode);//解除劃分 void DeleteTree(PBTreeNode pNode);//刪除樹 void Print(PBTreeNode pNode);//列印樹 }; void BTree::Insert(int key) { PBTreeNode r = root; if (r == NULL) { r = AllocateNode(); r->leaf = true; r->key_count = 0; root = r; } if (r != NULL && r->key_count == (2 * t - 1)) { PBTreeNode s = AllocateNode(); root = s; s->leaf = false; s->key_count = 0; s->child[1] = r; SplitChild(s, 1, r); InsertNonfull(s, key); } else { InsertNonfull(r, key); } cout << "成功插入關鍵字:" << key << endl; } bool BTree::Search(int key) { if (SearchBT(root, key)) return false; else return true; } PBTreeNode BTree::AllocateNode() { PBTreeNode pTemp = new BTreeNode; pTemp->key = new int[2 * t]; pTemp->child = new PBTreeNode[2 * t + 1]; //初始化 for (int i = 0; i < 2 * t; i++) { pTemp->key[i] = 0; pTemp->child[i] = NULL; } pTemp->child[2 * t] = NULL; return pTemp; } PBTreeNode BTree::SearchBT(PBTreeNode pNode, int key) { int i = 1; while (i <= pNode->key_count && key > pNode->key[i]) i++; if (i < pNode->key_count && key == pNode->key[i]) return pNode->child[i]; if (pNode->leaf) return NULL; else return SearchBT(pNode->child[i], key); } PBTreeNode BTree::UnionChild(PBTreeNode pParent, PBTreeNode pCLeft, PBTreeNode pCRight, int index) { for (int i = 1; i < t; i++) pCLeft->key[t + i] = pCRight->key[i]; pCLeft->key[t] = pParent->key[index]; for (int i = 1; i <= t; i++) pCLeft->child[t + i] = pCRight->child[i]; pCLeft->key_count = 2 * t - 1; for (int i = index; i < pParent->key_count; i++) pParent->key[i] = pParent->key[i + 1]; for (int i = index + 1; i <= pParent->key_count; i++) pParent->child[i] = pParent->child[i + 1]; pParent->key_count--; DeallocateNode(pCRight); if (pParent->key_count == 0) { DeallocateNode(root); root = pCLeft; } return pCLeft; } int BTree::Max(PBTreeNode pNode) { while (!pNode->leaf) { pNode = pNode->child[pNode->key_count + 1]; } return pNode->key[pNode->key_count]; } int BTree::Min(PBTreeNode pNode) { while (!pNode->leaf) { pNode = pNode->child[1]; } return pNode->key[1]; } void BTree::DeleteNonHalf(PBTreeNode pNode, int key) { int i = 1; while (i <= pNode->key_count && key > pNode->key[i]) i++; if (pNode->leaf) { if (i <= pNode->key_count && key == pNode->key[i]) { for (int j = i; j < pNode->key_count; j++) pNode->key[j] = pNode->key[j + 1]; pNode->key_count--; cout << "成功刪除關鍵字:" << key << endl; return; } else { //cout << "未能找到關鍵字:" << key << endl; return; } } if (i <= pNode->key_count && key == pNode->key[i]) { if (pNode->child[i]->key_count >= t) { key = Max(pNode->child[i]); pNode->key[i] = key; DeleteNonHalf(pNode->child[i], key); } else if (pNode->child[i + 1]->key_count >= t) { key = Min(pNode->child[i + 1]); pNode->key[i] = key; DeleteNonHalf(pNode->child[i + 1], key); } else { PBTreeNode pChild = UnionChild(pNode, pNode->child[i], pNode->child[i + 1], i); DeleteNonHalf(pChild, key); } } else if (pNode->child[i]->key_count == t - 1) { if (i > 1 && pNode->child[i - 1]->key_count >= t) { PBTreeNode pMidNode = pNode->child[i]; PBTreeNode pPreNode = pNode->child[i - 1]; int nPreNodeKeyCount = pPreNode->key_count; for (int j = pMidNode->key_count + 1; j > 1; j--) pMidNode->key[j] = pMidNode->key[j - 1]; pMidNode->key[1] = pNode->key[i - 1]; for (int j = pMidNode->key_count + 2; j > 1; j--) pMidNode->child[j] = pMidNode->child[j - 1]; pMidNode->child[1] = pPreNode->child[nPreNodeKeyCount + 1]; pMidNode->key_count++; pNode->key[i - 1] = pPreNode->key[nPreNodeKeyCount]; pPreNode->key[nPreNodeKeyCount] = 0; pPreNode->key[nPreNodeKeyCount + 1] = NULL; pPreNode->key_count--; DeleteNonHalf(pMidNode, key); } else if (i <= pNode->key_count && pNode->child[i + 1]->key_count >= t) { PBTreeNode pMidNode = pNode->child[i]; PBTreeNode pNextNode = pNode->child[i + 1]; int nNextNodeKeyCount = pNextNode->key_count; int nMidNodeKeyCount = pMidNode->key_count; pMidNode->key[nMidNodeKeyCount + 1] = pNode->key[i]; pMidNode->child[nMidNodeKeyCount + 2] = pNextNode->child[1]; pMidNode->key_count++; pNode->key[i] = pNextNode->key[1]; for (int j = 1; j < nNextNodeKeyCount; j++) pNextNode->key[j] = pNextNode->key[j + 1]; for (int j = 1; j <= nNextNodeKeyCount; j++) pNextNode->child[j] = pNextNode->child[j + 1]; pNextNode->key_count--; DeleteNonHalf(pMidNode, key); } else { if (i > pNode->key_count)//當i指向最後一個關鍵字時,合併時往前移動一步 i--; PBTreeNode pChild = UnionChild(pNode, pNode->child[i], pNode->child[i + 1], i); DeleteNonHalf(pChild, key); } } DeleteNonHalf(pNode->child[i], key); } void BTree::DeallocateNode(PBTreeNode pNode) { delete[] pNode->key; delete[] pNode->child; delete pNode; } void BTree::SplitChild(PBTreeNode pParent, int index, PBTreeNode pChild) { PBTreeNode pChildEx = AllocateNode(); pChildEx->leaf = pChild->leaf; pChildEx->key_count = t - 1; for (int j = 1; j < t; j++) pChildEx->key[j] = pChild->key[j + t]; if (!pChild->leaf) for (int j = 1; j <= t; j++) pChildEx->child[j] = pChild->child[j + t]; pChild->key_count = t - 1; for (int j = pParent->key_count + 1; j > index; j--) pParent->child[j + 1] = pParent->child[j]; pParent->child[index + 1] = pChildEx; for (int j = pParent->key_count; j >= index; j--) pParent->key[j + 1] = pParent->key[j]; pParent->key[index] = pChild->key[t]; pParent->key_count++; } void BTree::InsertNonfull(PBTreeNode pNode, int key) { int i = pNode->key_count; if (pNode->leaf) { while (i >= 1 && key < pNode->key[i]) { pNode->key[i + 1] = pNode->key[i]; i--; } pNode->key[i + 1] = key; pNode->key_count++; } else { while (i >= 1 && key < pNode->key[i]) i--; i++; if (pNode->child[i]->key_count == (2*t - 1)) { SplitChild(pNode, i, pNode->child[i]); if (key > pNode->key[i]) i++; } InsertNonfull(pNode->child[i], key); } } void BTree::DeleteTree(PBTreeNode pNode)//最後的根元素沒有被刪除,但是根裡的關鍵字陣列和孩子指標陣列已經刪除 { if (pNode->leaf) { delete[] pNode->key; delete[] pNode->child; } else { for (int i = 1; i <= pNode->key_count + 1; i++) { DeleteTree(pNode->child[i]); delete pNode->child[i]; } delete[] pNode->key; delete[] pNode->child; } } void BTree::Print(PBTreeNode pNode) { if (pNode->leaf) { cout << "葉子節點數目及成員:" << pNode->key_count << " "; for (int i = 1; i <= pNode->key_count; i++) { cout << pNode->key[i] << " "; } cout << endl; } else { for (int i = 1; i <= pNode->key_count + 1; i++) Print(pNode->child[i]); cout << "內部節點數目及成員:" << pNode->key_count << " "; for (int i = 1; i <= pNode->key_count; i++) { cout << pNode->key[i] << " "; } cout << endl; } } int main() { int num, n,data; cout << "請分別輸入關鍵字的個數及要建立的B樹的度數(中間用空格隔開):"; cin >> num >> n; BTree BT(n); cout << "請輸入" << num << "個建立B樹所需的關鍵字(中間用空格隔開):"; for (int i = num; i > 0; i--) { cin >> data; BT.Insert(data); } cout << "B樹建立成功!" << endl; BT.Display(); cout << "****************************************************************************" << endl; cin.ignore(1000, '\n'); char s,ss[100]; while (1) { cout << "請輸入操作(I:插入,D:刪除;以 ‘#’結束;多個數據間用空格隔開):" << endl; cin >> s; if (s == 'I') { while (cin >> ss && ss[0] != '#') { data = atoi(ss); /*if (BT.Search(data)) { cout << "關鍵字" << data << "已存在!" << endl; continue; }*/ BT.Insert(data); } BT.Display(); cout << "****************************************************************************" << endl; } else if (s == 'D') { while (cin >> ss && ss[0] != '#') { data = atoi(ss); /*if (BT.Search(data)==false) { cout << "未能找到關鍵字:" << data << endl; continue; }*/ BT.Delete(data); //cout << "成功刪除關鍵字:" << data << endl; } BT.Display(); cout << "****************************************************************************" << endl; } else cout << "輸入錯誤!" << endl; } return 0; } /* test data : 10 2 9 4 6 10 22 8 1 2 3 5 7 11 33 44 55 66 77 88 99 I 101 1001 111 1010 33 # D 8 33 10 # */