512 bytes/ record
2.2.2. Cỏc phộp toỏn trờn B-tree
Tỡm kiếm
Hỡnh 4.15
Xột node trong hỡnh 4.14, khoỏ caàntỡm là X. Giả sử nội dung của
node nằm trong bộ nhớ. Với m đủ lớnta sử dụng phương phỏp tỡm kiếm nhị phõn, nếu m nhỏ ta sử dụng phuơng phỏp tỡm kiếm tuần tự.
Nếu X khụng tỡm thấy sẽ cú ba trường hợp sau xảy ra:
i) Ki < X < Ki+1. Tiếp tục tỡm kiếm trõn cõy con Ci
ii) Km < X. Tiếp tục tỡm kiếm trờn Cm iii) X < K1. tiếp tục tỡm kiếm trờn C0
Quỏ trỡnh này tiếp tục cho đến khi node đỳngđược tỡm thấỵ Nếu đó đi đến node lỏ mà vẫn khụng tỡm thấy khoỏ, việc tỡm kiếm là thất
bạị
Phộp toỏn nodesearch
Trả về vị trớ nhỏ nhất của khúa trong nỳt current bắt đầu lớn hơn hay bằng k. Trường hợp k lớn hơn tất cả cỏc khúa trong nỳt current thỡ trả về vị trớ current-> numtrees-1
int nodesearch (pBNode current, int k) {
int i;
for(i=0;i< current->numtrees –1 && current- >key[i] < k; i++);
return (i);
}
Phộp toỏn nodesearchđược dựngđể tỡm khúa k cú trong nỳt current hay khụng. Nếu khúa k khụng cú trong nỳt current thỡ phộp toỏn này trả về vị trớ giỳp chỳng ta chọn nỳt con phự hợp của current để tiếp
tục tỡm khúa k trong nỳt con nàỵ
Phộp toỏn search
Tỡm khúa k trờn B-Treẹ Con trỏ current xuất phỏt từ gốc và đi xuống cỏc nhỏnh cõy con phự hợp để tỡm khúa k cú trong một nỳt current hay khụng.
Nếu cú khúa k tại nỳt current trờn cõy:
Biến foucunrrent tra về giỏ trị TRUE
Hàm search() trả về con trỏ chỉ nỳt current cú chứa khúa k
Biến positionition trả về vị trớ của khúa k cú trong nỳt current
này
Nếu khụng cú khúa k trờn cõy:
Lỳc này current=NULL và q(nỳt cha của current) chỉ nỳt lỏ cú thể
thờm khúa k vào nỳt nàyđược.
Biến foucunrrent trả về giỏ trị FALSE
Hàm search() trả về con trỏ q là nỳt lỏ cú thờm nỳt k vào
Biến positionition trả về vị trớ cú thể chốn khúa k vào nỳt lỏ q này
pBNode search(int k, int &positionition, int &foucunrrent) { int i; pBNode current, q; q = NULL; current = Root;
while (current !=NULL) {
i = nodesearch (current, k);
if(i< current->numtress–1 && k == current- >key[i]) //tim
thay
{
foucunrrent = TRUE;
positionition = i; // vi trớ tỡm thay khoa k
return(current); // node co chua khoa k
}q = current; q = current;
current = current ->Branch[i]; }
/*Khi thoat khoi vong lap tren la khong tim thay, luc nay current=NULL, q la node la co the them khoa k vao node nay, positionition la vi tri co the chen khoa k*/
foucunrrent = FALSE; positionition = i;
return (q); //tra ve node la
}
Phộp toỏn duyệt
Duyệt cỏc khúa của B-Tree theo thứ tự từ nhỏ đến lớn-bằng phương phỏpđệ qui
{
int i;
if(proot == NULL) //dieu kien dung
return;
else // de qui
{
/* vong lap duyet nhanh cay con Branch[i] va in khoa key[i] cua node proor*/
for(i = 0; i < proot -> numtress-1; i++) {
traverse (proot ->Branch[i]); printf (“%8d”, proot -> key[i]); }
//duyet nhanh cay con cuoi cung cua node proot
traverse (proot -> Branch[proot -> numtrees-1]); }
}
Thờm vào
Trước khi đưa ra giải thuật thờm một phần tử mới vào B- Tree, ta xem tỡnh huống cụ thể qua cỏc vớ dụ sau :
Vớ dụ 1:
- Thờm x=22 vào B-Tree ở hỡnh 4.15ạ Khúa 22 chưa cú trong cõy, nhưng khụng thể thờm vào node C vỡ node Cđóđầỵ
- Do đú tỏch node C thành hai node : node mới D được
cấp phỏt và m+1 khúađược chia đều cho 2 node C và D, và khúaở giữa được chuyển lờn node cha A : Hỡnh 4.15b
a)
b)
Hỡnh 4.16
Như vậy, việc thờm một khúa mới vào B-Tree cú thể gõy ra việc
tỏch node và việc tỏch node cú thể lan truyền ngược lờn node cha, trong trường hợp đặc biệt lan truyền đến tận gốc của B-Tree
Vớ dụ 2 : Xem quỏ trỡnh tạo B-Tree từ dóy cỏc khúa sau :
20; 40 10 30 15; 35 7 26 18 22; 5; 4 13 46 27 8 32; 38 24 45 25 Sau khi thờm vào khúa 30 :
Hỡnh 4.17 a
Khi thờm vào 15 thỡ node này bị đầy, do đú trường hợp này tạo
thành hai node mới : phần tử ở giữa là 20 bị đẩy lờn tạo thành một
node mới, cỏc phần tử cũn lại chia cho hai node : node cũ chứa 10,
15 và node mới thứ hai chứa 30,40 10, 20, 30, 40 20 7, 10, 15, 18 26, 30, 35, 40 A B C 20, 7, 10, 15, 18 22, 26 , 35, 40 A B C D
Hỡnh 4.17 b
Thờm vào cỏc khúa 35, 7,26 và 18.Đến khi thờm khúa 22 cũng cú sự đầy node dẫn đến việc tỏch node:
Hỡnh 4.17 c
Thờm vào 5 cũng cú sự đầy node (node đang chứa bốn khúa 7, 10,
15, 18) dẫn đến việc tỏch node :
Hỡnh 4.17 d
Thờm vào cỏc khúa 42, 13, 46, 27 và 8.Đến khi thờm 32 cú sự tỏch
node :
Hỡnh 4.17 e
Thờm vào 38, 24 và 45. Thờm 25 vào cú sự tỏch node và cho thấy
sự lan truyền tỏch node ngược lờn về phớa gốc : 25 thờm vào node (22, 24 26, 27) làm node này bị tỏch và 25 được đưa lờn node cha (10, 20, 30, 40) làm node này bị tỏch thành hai node và khoỏ 25 được đưa lờn thành node gốc mớị
Hỡnh 4.17 f Phộp toỏn insert 25 10, 20 30, 40 5, 7, 8 13, 15, 18 22, 24 26, 27 32, 35, 38 42, 45, 48 20 10, 15 30, 40 20, 30 7, 10, 15, 18 22, 26 35, 40 10, 20, 30 5, 7 15, 18 22, 26 35, 40 10, 20, 30, 40 5, 7, 8 13, 15, 18 22, 26, 27 32, 35 42, 46
Thờm khúa k vào vị trớ positionition của nỳt lỏ s (s và positionition do phộp toỏn search() trả về)
Nếu nỳt lỏ s chưađầy: gọi phộp toỏn insnode để chốn khúa k vào nỳt s
Nếu nỳt lỏ s đóđầy: tỏch nỳt lỏ này thành hai nỳt nửa trỏi và nửa
phải
void insert (pBNode s, int k, int positionition)
{
pBNode current, right_half, f, extra_branch; int positionition, extra_entry, median;
//khoi dong cac tri truoc khi vao vong lap tach cac node day current
current = s; extra_entry = k;
extra_branch = NULL; // vi current la node la nen gan
// extra_branch la NULL
positionition = positionition; f = father (current);
// Vong lap tach cac node day current
while (f != NULL && current -> numtrees == Order) {
split(current, extra_entry, extra_branch, positionition, right_half, median);
// Gan lai cac tri sau lan tach node truoc
current = f;
extra_entry = median; extra_branch = right_half;
positionition = nedesearch (f, median); f = father (current);
}
// Truong hop node current chua day va current khong phai la node goc
if(current - > numtrees < Order) {
//chen extra_entry va extra_branch tai vi tri positionition cua node current
insnode (current, extra_entry, extra_branch, positionition);
return; }
//Truong hop node current la node goc bi day, tach node goc nay va tao node goc moi
split (current, extra_entry, extra_branch, positionition, right_half, median);
Root = makeroot (median); // tao node goc moi
// Gan lai hai nhanh cay con cua node goc moi la current va right_half
Root -> Branch[0] = current; Root -> Branch[1] = right_half;
}
Khi thờm một khúa vào B-Tree chỳng ta cú thể viết nhưsau: printf(“\n Noi dung khoa moi: ”);
scanf(“%d”, &k);
// truong hop B-Tree bi rong khi tao node goc
if(Root == NULL)
Root = makeroot(k); else
{
s = search(k, &positionition, &timthay);if(timthay) if(timthay)
printf(“Bi trung khoa, khong them khoa %d vao
B-Tree duoc”, k); else
insert (s, k, positionition); }
Phộp split
Tỏch node đầy current, phộp toỏn nàyđược gọi bởi phộp toỏn Insert
current là nỳt đầy bị tỏch, sau khi tỏch xong nỳt current chỉ
cũn lại một nửa số khúa bờn trỏi
extra_entry, extra_branch và positionition là khúa mới,
nhỏnh cõy con và vị trớ chốn vào nỳt current
Nỳt right_half là nỳt nửa phải cú được sau lần tỏch, nỳt
right_half chiếm một nửa số khúa bờn phải
medianlà khúa ngay chớnh giữa sẽ đượcchốn vào nỳt cha
void split (pBNode current, int extra_entry, pBNode
extra_branch, int positionition, pBNode &right_half, int &median)
{
pBNode current;
current = new pBNode; //cap phat node nua phai /*truong hop chen extra_entry va extra_branch vao node nua phai*/
if(positionition > Order/2) {
copy(current, Order/2+1, Order – 2, current);
insnode (current, extra_entry, extra_branch,
positionition- Order/2 -1);
current->numtrees = Order/2+1; /*so nhanh cay con con lai cua node nua trai*/
median = current -> key[Order/2]; right_half = current;
return; }
// truong hop extra_entry la median
if(positionition == Order/2) {
copy(current, Order/2, Order-2, current);
current->numtrees = Order/2+1; /*so nhanh cay con con lai cua node nua trai*/
/*Dieu chinh lai node con dau tien cua node nua phai*/
current -> Branch[0] = extra_branch; median = current -> key[Order/2]; right_half = current;
return; }
/* Truong hop chen extra_entry va extra_branch vao node nua trai*/
if(positionition < Order/2) {
copy(current, Order/2, Order-2, current);
current->numtrees = Order/2; /*so nhanh cay con con lai cua node nua trai*/
median = current -> key[Order/2- 1]; insnode(current,extra_entry,extra_branch, positionition); right_half = current; return; } } Phộp toỏninsnode
Chốn khúa extra_entry vào vị trớ positionition của nỳt chưa đầy current, và chốn nhỏnh cõy con extra_branch vào vị trớ bờn phải cuả khúa extra_entry
void insnode (pBNode current, int extra_entry, pBNode extra_branch, int positionition)
{
int i;
/*doi cac nhanh cay con va cac khoa tu vi tri positionition tro ve sau xuong mot vi tri*/
for(i = current->numtress – 1; i >=
positionition+1; i--)
{
current -> Branch[i+1] = current ->
Branch[i];
current -> key[i] = current -> key[i - 1]; }
// gan khoa extra_entry vao vi tri positionition
current -> key[positionition] = extra_entry;
// Gan nhanh extra_branch la nhanh cay con ben phai cua khoa extra_entry
current -> Branch[positionition + 1] =
extra_branch;
//tang so nhanh cay con cua node current len 1
current -> numtrees +=1; }
Hỡnh 4.18-Thao tỏc InsNode
Hỡnh 4.19Tỏch một Node đầy
Chộp cỏc khúa (và nhỏnh cõy con) từ vị trớ first đến vị trớ fast của nỳt current (nỳt nửa trỏi) sang nỳt right_half (nửa nỳt phải) . Phộp toỏn nàyđược gọi bởi phộp toỏn split
void copy(pBNode current, int first, int last, NODPTR right_half)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ++++++++++++++++++++++++++++++++++++++++++++++++++*/ {
int i;
// copy cac khoa tu node current qua node right_half
for(i = first; i < last, i++)
right_half->key[i-first]=current -> key[i];
// copy cac nhanh cay con tu node current qua right_half
for(i = first; i < last+1, i++)
right_half->Branch[i-first]=current -> Branch[i];
right_half ->numtrees = last – first +2 // so
nhanh cay con cua node right_half
}
Phộp toỏn loại bỏ
pBNode remove(const int &key)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++Kết quả: Nếu tỡm thấy khúa key sẽ xoỏ khúa này và trả về địa chỉ Kết quả: Nếu tỡm thấy khúa key sẽ xoỏ khúa này và trả về địa chỉ
node chứa key, nếu khụng tỡm thấy trả về NULL
Sử dụng hàmđệ quy recursive_remove()
++++++++++++++++++++++++++++++++++++++++++++++++++++*/{ {
PBNode result = recursive_remove(root, key);
if (root != NULL && root->numtress == 0) {
pDNode old_root = root; root = root->branch[0];
delete old_root; }
return result; }
Hỡnh 4.20-Loại bỏ trờn B-tree
pBNode recursive_remove(pBNode current, const int &key)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++c current hoặc rỗng hoặc là con trỏ đến cõy con.
Hàm này Thực hiện xoỏ key nếu tỡm thấy khoỏ key, ngược lại trả về NULL
Sử dụng cỏc hàm nodesearch(), copy_in_predecessor(), recursive_remove (recursively), remove_dată)và restore().
++++++++++++++++++++++++++++++++++++++++++++++++++++*/{ {
int positionition; PBNode result;
if (current == NULL) return NULL; else
{
if (search(current, key, positionition)) {
// Tỡm thấy key trong node current.
if (current->branch[positionition] != NULL)
{ // khụng phải là node lỏ
copy_in_predecessor(current, positionition);
result=recursive_remove(current- >branch[positionition],current- >data[positionition]);
}
else remove_data(current,
positionition);//Xoỏ tại node lỏ
}
else result = recursive_remove(current- >branch[positionition], key);
if (current->branch[positionition] != NULL)
if (current->branch[positionition]->numtress <(order - 1)/2)
restore(current, positionition); }
return result; }
void remove_datăpBNode current,int positionition)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++Xúa tại vị trớ positionition trờn node lỏ current. Xúa tại vị trớ positionition trờn node lỏ current. +++++++++++++++++++++++++++++++++++++++++++++++++++*/ {
for (int i = positionition; i < current->numtress - 1; i++)
current->data[i] = current->data[i + 1]; current->numtress --;
}
void copy_in_predecessor(pBNode current, int positionition)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++Tại vị trớ positionition trờn node current(current Tại vị trớ positionition trờn node current(current khụng phải là lỏ ) sẽ được thay bởi khoỏ key cực phải của cõy con bờn trỏi của current)
+++++++++++++++++++++++++++++++++++++++++++++++++++*/
{
pBNode leaf = current->branch[positionition]; while (leaf->branch[leaf->numtress ] != NULL)
leaf = leaf->branch[leaf->numtress ]; current->data[positionition]=leaf->data[leaf- >numtress-1];
}
void restore(pBNode current,int positionition)
/*++++++++++++++++++++++++++++++++++++++++++++++++++Sữ dụng cỏc hàm: move_left, move_right, combine. Sữ dụng cỏc hàm: move_left, move_right, combine. ++++++++++++++++++++++++++++++++++++++++++++++++++*/ { if(positionition==current->numtress) //Trường hợp nhỏnh cực phải if(current->branch[positionition-1]->numtress>(order- )/ 2)
move_right(current, positionition - 1); else
combine(current, positionition); else if (positionition == 0) // Trường hợp nhỏnh cực trỏi if (current->branch[1]->numtress > (order - 1) / 2) move_left(current, 1); else combine(current, 1); else //cỏc trường hợp khỏc: nhỏnh giữa if(current->branch[positionition-1]->numtress>(order- 1)/ 2)
move_right(current, positionition - 1);
else if(current->branch[positionition+1]-
>numtress>(order- 1) / 2)
move_left(current, positionition + 1); else
combine(current, positionition); }
void move_left(pBNode current,int positionition)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ++++++++++++++++++++++++++++++++++++++++++++++++++*/ {pBNode left_branch = current->branch[positionition - 1];
pBNode right_branch = current->branch[positionition]; left_branch->data[left_branch->numtress ] = current- >data[positionition - 1]; left_branch->branch[++left_branch->numtress ] = right_branch->branch[0]; current->data[positionition - 1] = right_branch- >data[0]; right_branch->numtress --;
for (int i = 0; i < right_branch->numtress ; i++) {
right_branch->data[i]=right_branch->data[i + 1];
right_branch->branch[i]=right_branch-branch[i+1]; }
right_branch->branch[right_branch->numtress + 1]; }
void move_right(pBNode current,int positionition)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ++++++++++++++++++++++++++++++++++++++++++++++++++*/ {
pBNode right_branch = current->branch[positionition + 1];
pBNode left_branch = current->branch[positionition]; right_branch->branch[right_branch->numtress + 1] =
right_branch->branch[right_branch->numtress ]; for (int i = right_branch->numtress ; i > 0; i--)
{ right_branch->data[i]=right_branch->data[i - 1]; right_branch->data[i]=right_branch->data[i - 1]; right_branch->branch[i]=right_branch->branch[i-1]; } right_branch->numtress ++; right_branch->data[0] = current- >data[positionition]; right_branch- >branch[0]=left_branch-branch[left_branch- >numtress - -]; current->data[positionition]= left_branch- >data[left_branch->numtress ]; }
void combine(pBNode current,int positionition)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ++++++++++++++++++++++++++++++++++++++++++++++++++*/ {
int i;
pBNode left_branch = current->branch[positionition - 1];
pBNode right_branch = current->branch[positionition]; left_branch->data[left_branch->numtress ] = current- >data[positionition - 1];
left_branch->branch[++left_branch->numtress ] =
right_branch->branch[0];
for (i = 0; i < right_branch->numtress ; i++) { left_branch->data[left_branch->numtress]= right_branch->data[i]; left_branch->branch[++left_branch->numtress ] = right_branch->branch[i + 1]; } current->numtress --;
for (i = positionition - 1; i < current->numtress ; i++) { current->data[i] = current->data[i + 1]; current->branch[i + 1] = current->branch[i + 2]; } delete right_branch; } Hỡnh 4.21-move_right, combine