1. 程式人生 > >[轉]B+樹的結構和實現程式碼

[轉]B+樹的結構和實現程式碼

/*******************************************************//* btrees.c */ 
#include 
#include 
#include 
"btrees.h" 

btree search(typekey, btree); 
btree insert(typekey,btree); 
btree delete(typekey,btree); 
int height(btree); 
int count(btree); 
double payload(btree); 
btree deltree(btree); 

staticvoid InternalInsert(typekey, btree); 
staticvoid InsInNode(btree, int); 
staticvoid SplitNode(btree, int); 
static btree NewRoot(btree); 

staticvoid InternalDelete(typekey, btree); 
staticvoid JoinNode(btree, int); 
staticvoid MoveLeftNode(btree t, int); 
staticvoid MoveRightNode(btree t, int); 
staticvoid DelFromNode(btree t, int); 
static btree FreeRoot(btree); 

static btree delall(btree); 
staticvoid Error(int,typekey); 

int btree_disp; /* 查詢時找到的鍵在節點中的位置 */char* InsValue = NULL; /* 與要插的鍵相對應的值 */staticint flag; /* 節點增減標誌 */staticint btree_level =0/* 多路樹的高度 */staticint btree_count =0/* 多路樹的鍵總數 */staticint node_sum =0/* 多路樹的節點總數 */staticint level; /* 當前訪問的節點所處的高度 */static
 btree NewTree; /* 在節點分割的時候指向新建的節點 */static typekey InsKey; /* 要插入的鍵 */ 

btree search(typekey key, btree t) 

int i,j,m; 
level
=btree_level-1
while (level >=0){ 
for(i=0, j=t->d-1; i t->k[m])?(i=m+1):(j=m)); 
if (key == t->k){ 
btree_disp 
= i; 
return t; 

if (key > t->k) /* i == t->d-1 時有可能出現 */ 
i
++
= t->p; 
level
--

return NULL; 


btree insert(typekey key, btree t) 

level
=btree_level; 
InternalInsert(key, t); 
if (flag ==1/* 根節點滿之後,它被分割成兩個半滿節點 */ 
t
=NewRoot(t); /* 樹的高度增加 */return t; 


void InternalInsert(typekey key, btree t) 

int i,j,m; 

level
--
if (level <0){ /* 到達了樹的底部: 指出要做的插入 */ 
NewTree 
= NULL; /* 這個鍵沒有對應的子樹 */ 
InsKey 
= key; /* 導致底層的葉子節點增加鍵值+空子樹對 */ 
btree_count
++
flag 
=1/* 指示上層節點把返回的鍵插入其中 */return

for(i=0, j=t->d-1; i t->k[m])?(i=m+1):(j=m)); 
if (key == t->k) { 
Error(
1,key); /* 鍵已經在樹中 */ 
flag 
=0
return

if (key > t->k) /* i == t->d-1 時有可能出現 */ 
i
++
InternalInsert(key, t
->p); 

if (flag ==0
return
/* 有新鍵要插入到當前節點中 */if (t-><2*M) {/* 當前節點未滿 */ 
InsInNode(t, i); 
/* 把鍵值+子樹對插入當前節點中 */ 
flag 
=0/* 指示上層節點沒有需要插入的鍵值+子樹,插入過程結束 */ 

else/* 當前節點已滿,則分割這個頁面並把鍵值+子樹對插入當前節點中 */ 
SplitNode(t, i); 
/* 繼續指示上層節點把返回的鍵值+子樹插入其中 */ 


/* 
* 把一個鍵和對應的右子樹插入一個節點中 
*/void InsInNode(btree t, int d) 

int i; 
/* 把所有大於要插入的鍵值的鍵和對應的右子樹右移 */for(i = t->d; i > d; i--){ 
t
->= t->k[i-1]; 
t
->= t->v[i-1]; 
t
->p[i+1= t->p; 

/* 插入鍵和右子樹 */ 
t
->= InsKey; 
t
->p[i+1= NewTree; 
t
->= InsValue; 
t
->d++

/* 
* 前件是要插入一個鍵和對應的右子樹,並且本節點已經滿 
* 導致分割這個節點,插入鍵和對應的右子樹, 
* 並向上層返回一個要插入鍵和對應的右子樹 
*/void SplitNode(btree t, int d) 

int i,j; 
btree temp; 
typekey temp_k; 
char*temp_v; 
/* 建立新節點 */ 
temp 
= (btree)malloc(sizeof(node)); 
/* 
* +---+--------+-----+-----+--------+-----+ 
* | 0 | ...... | M | M+1 | ...... |2*M-1| 
* +---+--------+-----+-----+--------+-----+ 
* |<- M+1 ->|<- M-1 ->| 
*/if (d > M) { /* 要插入當前節點的右半部分 *//* 把從 2*M-1 到 M+1 的 M-1 個鍵值+子樹對轉移到新節點中, 
* 並且為要插入的鍵值+子樹空出位置 
*/for(i=2*M-1,j=M-1; i>=d; i--,j--) { 
temp
->k[j] = t->k; 
temp
->v[j] = t->v; 
temp
->p[j+1= t->p[i+1]; 

for(i=d-1,j=d-M-2; j>=0; i--,j--) { 
temp
->k[j] = t->k; 
temp
->v[j] = t->v; 
temp
->p[j+1= t->p[i+1]; 

/* 把節點的最右子樹轉移成新節點的最左子樹 */ 
temp
->p[0= t->p[M+1]; 
/* 在新節點中插入鍵和右子樹 */ 
temp
->k[d-M-1= InsKey; 
temp
->p[d-M] = NewTree; 
temp
->v[d-M-1= InsValue; 
/* 設定要插入上層節點的鍵和值 */ 
InsKey 
= t->k[M]; 
InsValue 
= t->v[M]; 


else { /* d <= M *//* 把從 2*M-1 到 M 的 M 個鍵值+子樹對轉移到新節點中 */for(i=2*M-1,j=M-1; j>=0; i--,j--) { 
temp
->k[j] = t->k; 
temp
->v[j] = t->v; 
temp
->p[j+1= t->p[i+1]; 

if (d == M) /* 要插入當前節點的正中間 *//* 把要插入的子樹作為新節點的最左子樹 */ 
temp
->p[0= NewTree; 
/* 直接把要插入的鍵和值返回給上層節點 */else { /* (d /* 把節點當前的最右子樹轉移成新節點的最左子樹 */ 
temp
->p[0= t->p[M]; 
/* 儲存要插入上層節點的鍵和值 */ 
temp_k 
= t->k[M-1]; 
temp_v 
= t->v[M-1]; 
/* 把所有大於要插入的鍵值的鍵和對應的右子樹右移 */for(i=M-1; i>d; i--) { 
t
->= t->k[i-1]; 
t
->= t->v[i-1]; 
t
->p[i+1= t->p; 

/* 在節點中插入鍵和右子樹 */ 
t
->k[d] = InsKey; 
t
->p[d+1= NewTree; 
t
->v[d] = InsValue; 
/* 設定要插入上層節點的鍵和值 */ 
InsKey 
= temp_k; 
InsValue 
= temp_v; 


t
->=M; 
temp
->= M; 
NewTree 
= temp; 
node_sum
++


btree delete(typekey key, btree t) 

level
=btree_level; 
InternalDelete(key, t); 
if (t->==0
/* 根節點的子節點合併導致根節點鍵的數目隨之減少, 
* 當根節點中沒有鍵的時候,只有它的最左子樹可能非空 
*/ 
t
=FreeRoot(t); 
return t; 


void InternalDelete(typekey key, btree t) 

int i,j,m; 
btree l,r; 
int lvl; 

level
--
if (level <0) { 
Error(
0,key); /* 在整個樹中未找到要刪除的鍵 */ 
flag 
=0
return

for(i=0, j=t->d-1; i t->k[m])?(i=m+1):(j=m)); 
if (key == t->k) { /* 找到要刪除的鍵 */if (t->!= NULL) 
free(t
->v); /* 釋放這個節點包含的值 */if (level ==0) { /* 有子樹為空則這個鍵位於葉子節點 */ 
DelFromNode(t,i); 
btree_count
--
flag 
=1
/* 指示上層節點本子樹的鍵數量減少 */return
else { /* 這個鍵位於非葉節點 */ 
lvl 
= level-1
/* 找到前驅節點 */ 
= t->p; 
while (lvl >0) { 
= r->p[r->d]; 
lvl
--

t
->k=r->k[r->d-1]; 
t
->v=r->v[r->d-1]; 
r
->v[r->d-1]=NULL; 
key 
= r->k[r->d-1]; 


elseif (key > t->k) /* i == t->d-1 時有可能出現 */ 
i
++
InternalDelete(key,t
->p); 
/* 調整平衡 */if (flag ==0
return
if (t->p->< M) { 
if (i == t->d) /* 在最右子樹中發生了刪除 */ 
i
--/* 調整最右鍵的左右子樹平衡 */ 
= t->p; 
= t->p[i+1]; 
if (r->> M) 
MoveLeftNode(t,i); 
elseif(l->> M) 
MoveRightNode(t,i); 
else { 
JoinNode(t,i); 
/* 繼續指示上層節點本子樹的鍵數量減少 */return

flag 
=0
/* 指示上層節點本子樹的鍵數量沒有減少,刪除過程結束 */ 



/* 
* 合併一個節點的某個鍵對應的兩個子樹 
*/void JoinNode(btree t, int d) 

btree l,r; 
int i,j; 
= t->p[d]; 
= t->p[d+1]; 

/* 把這個鍵下移到它的左子樹 */ 
l
->k[l->d] = t->k[d]; 
l
->v[l->d] = t->v[d]; 
/* 把右子樹中的所有鍵值和子樹轉移到左子樹 */for (j=r->d-1,i=l->d+r->d; j >=0 ; j--,i--) { 
l
->= r->k[j]; 
l
->= r->v[j]; 
l
->= r->p[j]; 

l
->p[l->d+r->d+1= r->p[r->d]; 
l
->+= r->d+1
/* 釋放右子樹的節點 */ 
free(r); 
/* 把這個鍵右邊的鍵和對應的右子樹左移 */for (i=d; i < t->d-1; i++) { 
t
->= t->k[i+1]; 
t
->= t->v[i+1]; 
t
->p[i+1= t->p[i+2]; 

t
->d--
node_sum
--

/* 
* 從一個鍵的右子樹向左子樹轉移一些鍵,使兩個子樹平衡 
*/void MoveLeftNode(btree t, int d) 

btree l,r; 
int m; /* 應轉移的鍵的數目 */int i,j; 
= t->p[d]; 
= t->p[d+1]; 
= (r->- l->d)/2

/* 把這個鍵下移到它的左子樹 */ 
l
->k[l->d] = t->k[d]; 
l
->v[l->d] = t->v[d]; 
/* 把右子樹的最左子樹轉移成左子樹的最右子樹 
* 從右子樹向左子樹移動 m-1 個鍵+子樹對 
*/for (j=m-2,i=l->d+m-1; j >=0; j--,i--) { 
l
->= r->k[j]; 
l
->= r->v[j]; 
l
->= r->p[j]; 

l
->p[l->d+m] = r->p[m-1]; 
/* 把右子樹的最左鍵提升到這個鍵的位置上 */ 
t
->k[d] = r->k[m-1]; 
t
->v[d] = r->v[m-1]; 
/* 把右子樹中的所有鍵值和子樹左移 m 個位置 */ 
r
->p[0= r->p[m]; 
for (i=0; id-m; i++) { 
r
->= r->k[i+m]; 
r
->= r->v[i+m]; 
r
->= r->p[i+m]; 

r
->p[r->d-m] = r->p[r->d]; 
l
->d+=m; 
r
->d-=m; 

/* 
* 從一個鍵的左子樹向右子樹轉移一些鍵,使兩個子樹平衡 
*/void MoveRightNode(btree t, int d) 

btree l,r; 
int m; /* 應轉移的鍵的數目 */int i,j; 
= t->p[d]; 
= t->p[d+1]; 

= (l->- r->d)/2
/* 把右子樹中的所有鍵值和子樹右移 m 個位置 */ 
r
->p[r->d+m]=r->p[r->d]; 
for (i=r->d-1; i>=0; i--) { 
r
->k[i+m] = r->k; 
r
->v[i+m] = r->v; 
r
->p[i+m] = r->p; 

/* 把這個鍵下移到它的右子樹 */ 
r
->

相關推薦

[]B+結構實現程式碼

/*******************************************************//* btrees.c */ #include #include #include "btrees.h" btree search(typekey, btree); btree insert(ty

MySQL B+索引哈希索引的區別( JD二面)

不同的應用 not null 效率比較 xxx apt link int data- 創建 導讀 在MySQL裏常用的索引數據結構有B+樹索引和哈希索引兩種,我們來看下這兩種索引數據結構的區別及其不同的應用建議。 二者區別 備註:先說下,在MySQL文檔裏,實際上是把B

B 插入 刪除 圖文 程式碼實現 golang實現

一、B樹的定義 B樹也稱B-樹,它是一顆多路平衡查詢樹。我們描述一顆B樹時需要指定它的階數,階數表示了一個結點最多有多少個孩子結點,一般用字母m表示階數。當m取2時,就是我們常見的二叉搜尋樹。 一顆m階的B樹定義如下: 1、每個結點最多有m-1個關鍵字。 2、根結點最少可

資料庫為什麼要用B+結構--MySQL索引結構實現

為什麼使用B+樹?言簡意賅,就是因為: 1.檔案很大,不可能全部儲存在記憶體中,故要儲存到磁碟上 2.索引的結構組織要儘量減少查詢過程中磁碟I/O的存取次數(為什麼使用B-/+Tree,還跟磁碟存取原理有關。) 3.區域性性原理與磁碟預讀,預讀的長度一般為頁(page)的整

資料結構與演算法——B的C++實現

It is recommended to refer following posts as prerequisite of this post. B-Tree is a type of a multi-way search tree. So, if you are not familiar with

【資料結構】平衡搜尋之---B的演算法實現

#include<iostream> using namespace std; #ifndef __BTREE_H__ #define __BTREE_H__ template<class K,int M=3>//設為三階B樹(每個陣列三個關鍵字

【資料結構(四):B(C++實現

> 《演算法導論》學習 基本介紹 B樹是為磁碟或者其他直接存取的輔助儲存(secondary storage)裝置而設計的平衡搜尋樹。B樹類似於紅黑樹,但是在降低磁碟I/O運算元方面表現更好。許多資料庫系統使用B樹或其變種來儲存資訊。 一個

二叉的儲存結構實現

一、二叉樹儲存結構 1)二叉樹的順序儲存結構  二叉樹的順序儲存結構中節點的存放次序是:對該樹中每個節點進行編號,其編號從小到大的順序就是節點存放在連續儲存單元的先後次序。 若把二叉樹儲存到一維陣列中,則該編號就是下標值加1(注意C/C++語言中陣列的起始下標為0)。樹中各節

《MySQL實戰45講》學習筆記3——InnoDB為什麼採用B+結構實現索引

索引的作用是提高查詢效率,其實現方式有很多種,常見的索引模型有雜湊表、有序列表、搜尋樹等。 雜湊表 一種以key-value鍵值對的方式儲存資料的結構,通過指定的key可以找到對應的value。 雜湊把值放在數組裡,用一個雜湊函式把key換算成一個確定位置,然後把value放在陣列的這個位置。但是,多個ke

看得見的資料結構Android版之二分搜尋結構實現

零、前言 1.個人感覺這個二叉搜尋樹實現的還是很不錯的,基本操作都涵蓋了 2.在Activity中對view設定監聽函式,可以動態傳入資料,只要可比較,都可以生成二分搜尋樹 3.二分搜尋樹的價值:搜尋、新增、刪除、更新速度快,最佳狀態複雜度logn,但極端情況下會退化成單鏈表 4.本例操作演示原始碼:

程式設計基礎79 給定二叉排序結構陣列求整棵

1099 Build A Binary Search Tree (30 分) A Binary Search Tree (BST) is recursively defined as a binary tree which has the following properties: T

資料結構結構實現--二叉鏈式結構(C語言)

學習參考: 嚴蔚敏: 《資料結構-C語言版》 基本操作 建立二叉樹 先序遍歷(遞迴) 中序遍歷(遞迴) 後序遍歷(遞迴) 層次遍歷 先序遍歷(非遞迴) 中序遍歷(非遞迴) 後序遍歷(非遞迴) 查詢 改進版查詢 求樹的深度 求葉子結點 求結點數

二叉基礎操作 ,前中後序遍歷,求二叉高度,二叉搜尋(二叉排序)Java實現 程式碼集合

首先,定義一個樹類Tree.java public class Tree { public TreeNode root; } 定義樹節點類TreeNode.java public class TreeNode { public TreeNode(int

雜湊儲存、B儲存LSM儲存引擎

1、雜湊儲存引擎  是雜湊表的持久化實現,支援增、刪、改以及隨機讀取操作,但不支援順序掃描,對應的儲存系統為key-value儲存系統。對於key-value的插入以及查詢,雜湊表的複雜度都是O(1),明顯比樹的操作O(n)快,如果不需要有序的遍歷資料,雜湊表就是your M

B(或B-B+B*(不看後悔,一看必懂)

樹的深度過大而造成磁碟I/O讀寫過於頻繁,進而導致查詢效率低下 根據平衡二叉樹的啟發,自然就想到平衡多路查詢樹結構,即B樹結構(後面,我們將看到,B樹的各種操作能使B樹保持較低的高度,從而達到有效避免磁碟過於頻繁的查詢存取操作,從而有效提高查詢效率)。 為什麼說B+tre

B+的Java實現

下面的B+樹演算法是在我學習了別人的程式碼之後經過修改完成的,主要在葉子節點上使用了二分查詢,另外在更新節點上也減少了部分的遞迴操作,還對節點的結構做了細微的修改(每個節點得孩子指標比關鍵碼多1,原來是孩子指標和關鍵碼一樣多,這也與B+樹的原本定義一致),應該說整個程式的邏

圖解B+B-特點對比總結

B+樹和B-樹總結: B+ 樹是B-樹的變體,也是一種多路搜尋樹 B+樹與B-樹相同點在於: 1. 對於一顆M階B+和B-樹來說,根節點的分支數範圍為[2,m],非根結點的分支數範圍為[m/2(向上取整),m] 2. 所有葉子結點都在同一層 3. 插入操作都是在葉子結點完成(破壞結構後再向上調整

B+C語言實現

B+樹C語言版本,編譯通過,測試正確 插入部分實現,其中刪除和插入類似 #include<stdlib.h> #include<stdio.h> #include<stdbool.h> #include<string.h>

MySQL B+索引哈希索引的區別

掃描 pad 不同的 tab ble 這不 只需要 網絡 adapt 導讀 在MySQL裏常用的索引數據結構有B+樹索引和哈希索引兩種,我們來看下這兩種索引數據結構的區別及其不同的應用建議。 二者區別 備註:先說下,在MySQL文檔裏,實際上是把B+樹索引寫成了BTRE

B-的C++實現

程式碼下載:http://bluedog.download.csdn.net B-樹網上的程式碼很象不是很多,關於它的原理我覺得沒有必要要談了,書上網上太多了。這裡我花了幾天的時間寫了一個,大家覺得有用的話就用吧,已經進行大量的測試,應該沒有什麼太大問題了,它由兩個檔案定義:BinaryMinusTre