B樹 (插入操作)
阿新 • • 發佈:2018-12-25
B樹
B樹的特性
一顆m階的B樹滿足一下特性
(一) 樹中的每個結點至多有m顆子樹,至少有顆子樹。(除根結點和葉子結點外),其中表示m/2向上取整。()
(二) 樹中的每個結點至少有個關鍵字,至多m-1個關鍵字。
當結點的關鍵字個數滿時,那麼該結點就需要分裂,如何分裂?
假設*p結點已經有m-1個關鍵字,當再插入一個關鍵字後,其關鍵字個數為m,超標了!分裂開始,將*p結點分裂成兩個結點,分別是*p,*。其中*p結點有個關鍵字,分別為,其中C表示孩子指標,K表示關鍵字,下表是個數。那麼*結點有個關鍵字,分別為。關鍵字和指標*一起插入到*p的雙親結點中,如下圖所示。
假設是4階B樹,*p結點已經有3個關鍵字,當再插入一個關鍵字Q時,*p結點關鍵字個數超標,需要分裂,分裂結果如下。
分析,因為是4階B樹,所以。
其中*p結點有=1個關鍵字,對應為結點H。
*結點有個關鍵字,對應N,Q。
關鍵字和指標*一起插入到*p的雙親結點中。
再通俗點講就是,當在葉子結點插入一個元素時,判斷葉子結點空間是否已滿?
1. 當葉子結點空間未滿時,只需要將葉子結點中關鍵字大於插入元素的位置都向後移動一位,留下的那個空位就放這個新插入的元素。
2. 當葉子結點空間已滿時,就需要分裂,將該葉子結點個元素分裂到其相鄰的右結點中,第個元素上跳到雙親結點中,並在適當的位置插入,當然,插入後雙親結點原先的元素及指標位置都要往後移動一位。(如果,此時雙親結點的空間也滿了,那麼也要做分裂操作)。
3. 如果是在根結點中插入元素,跟結點的空間滿了,那麼需要將第個元素上跳給新的根結點,這樣樹的高度就增加1。
// B-Tree.cpp : Defines the entry point for the console application. /*-----CODE FOR FUN--------------- -------CREATED BY Dream_Whui------ -------2015-3-22-------------------------*/ //B樹(插入及遍歷) #include "stdafx.h" #include <iostream> typedef int KeyType; //定義鍵值型別 #define ORDER 4 //階數 #define BTree_D 2 //[OREDR/2]向上取整 typedef struct BTNode { int keynum; //鍵的個數 KeyType key[ORDER-1];//結點關鍵字個數[BTree_D-1,ORDER-1] BTNode *child[ORDER];//結點孩子數[BTree_D,ORDER](除根節點與葉子節點) bool isLeaf; //是否為孩子結點 }BTNode, *BTree; void Tree_split_child(BTree &parent, int index, BTree &node); void BTree_insert_nonfull(BTree &node, KeyType key)//在node中插入關鍵字key { int i; if(node->isLeaf) //若是葉子結點,則直接插入 { i = node->keynum-1; while(i>=0 && key<node->key[i]) { node->key[i+1] = node->key[i]; i--; } node->key[i+1] = key; node->keynum++; } else //不是葉子結點,先找到插入的位置i { i = node->keynum-1; while(i>=0 && key<node->key[i]) i--; i++; if(node->child[i]->keynum == (ORDER-1))//判斷插入的位置i,其孩子結點的關鍵字個數是否已滿 { Tree_split_child(node, i, node->child[i]);//滿了,則分裂 if(key > node->key[i] ) //分裂完成後,重新判斷key與node->key[i]的大小,決定應該插入帶第i個孩子結點還是第i+1個孩子結點 i++; } BTree_insert_nonfull(node->child[i], key); } } void Tree_split_child(BTree &parent, int index, BTree &node) { BTree newNode = (BTree)malloc(sizeof(BTNode));//產生一個新結點newNode,存放node的最後ORDER-BTree_D個關鍵字 if(!newNode) return; newNode->isLeaf = node->isLeaf; //newNode與node在同一層,因此兩者葉子節點屬性相同 newNode->keynum = BTree_D -1; //新結點關鍵字個數為BTree_D -1 for(int i=0; i<ORDER; i++) //新結點的孩子初始化為空 newNode->child[i] = NULL; int i; for(i=0; i<newNode->keynum; i++) //賦值新結點的關鍵字為node最後ORDER-BTree_D個關鍵字 { newNode->key[i] = node->key[BTree_D + i]; node->key[BTree_D + i] = 0; } if(!node->isLeaf) //如果不是葉子結點,是內部結點 { for(i=0; i<BTree_D; i++)// { newNode->child[i] = node->child[BTree_D + i]; node->child[BTree_D + i] = NULL; } } node->keynum = BTree_D -1; //node關鍵字個數為BTree_D -1 for (i = parent->keynum; i > index; --i) //因為不是在parent末尾插入關鍵字,因此從第i個孩子開始都網後移動一個位置 { parent->child[i + 1] = parent->child[i]; } parent->child[index+1] = newNode;//因為第index個孩子發生了分裂,因此第index+1個孩子指向新的結點 for (i = parent->keynum - 1; i >= index; --i) //同理,parent從第index個關鍵字也往後移動一個位置 { parent->key[i + 1] = parent->key[i]; } parent->key[index] = node->key[BTree_D-1];//移動完後,第index個位置上的元素為node的第BTree_D-1關鍵字 parent->keynum++; node->key[BTree_D-1] = 0; } void BTree_Insert(BTree &tree, KeyType key)//在B樹中插入關鍵字key { BTree node; BTree root = tree; if(NULL == root) //根節點空,即第一次插入關鍵字 { root = (BTree)malloc(sizeof(BTNode)); if(!root) return; root->keynum = 1; //鍵個數為1 root->isLeaf = true; //根節點又是葉子節點 root->key[0] = key; //第一個鍵值為key for(int i=0; i<ORDER; i++) //它的孩子結點初始化為空 root->child[i] = NULL; tree = root; return; } if(root->keynum == (ORDER-1)) //根結點的關鍵字個數已滿,即要分裂 { node = (BTree)malloc(sizeof(BTNode));//產生一個新結點,作為根結點 if(!node) return; tree = node; node->keynum = 0; //新的根節點關鍵字個數初始化為0個 node->isLeaf = false; //非葉子節點 node->child[0] = root; //其左孩子是原先的根結點 Tree_split_child(node, 0, root);//分裂 BTree_insert_nonfull(node, key); } else //根結點的關鍵字個數未滿 BTree_insert_nonfull(root, key); } void Tree_Print(BTree tree, int layer=1)//B樹遍歷 { BTree node = tree; int i; if(node) { printf("第 %d 層, %d node : ", layer, node->keynum); for(i=0; i<node->keynum; i++) { printf("%d", node->key[i]); } printf("\n"); layer++; for(i=0; i<=node->keynum; i++) { if(node->child[i]) Tree_Print(node->child[i], layer); } } else { printf("樹為空。\n"); } } int _tmain(int argc, _TCHAR* argv[]) { BTree tree = NULL; BTree_Insert(tree,1); BTree_Insert(tree,2); BTree_Insert(tree,3); BTree_Insert(tree,4); BTree_Insert(tree,5); BTree_Insert(tree,6); BTree_Insert(tree,7); BTree_Insert(tree,8); BTree_Insert(tree,9); BTree_Insert(tree,10); Tree_Print(tree); return 0; }