512 bytes/ record
2.4. B-tree và bộ nhớ ngoà
Giới thiệu
Để tiết kiệm bộ nhớ trong, người ta thường tổ chức B-Treeở bộ nhớ
ngoài (đĩa từ, băng từ,…); khi truy xuất B-Tree người ta chỉ nạp
một phần nhỏ của B-Tree vào bộ nhớ trong để xử lý.
Tất cả cỏc nỳt trờn B-Tree lỳc nàyđược lưu trữ ở bộ nhớ ngoài, mỗi
nỳt cũng chứa cỏc thụng tin như : số nhỏnh cõy con của nỳt
(numtrees), cỏc khúa cú trong nỳt (key[]), cỏc địa chỉ của cỏc nỳt
Branch (Branch []).
Ngũai ra chỳng ta cần biết những thụng tinđể quản lý B-Treeở bộ
nhớ ngũai như địa chỉ của nỳt gốc, số nỳt hiện cú trờn B-Tree,… Những thụng tin này cú thể lưu ở bộ nhớ ngũai hayđược xỏc định
trong chuơng trỡnh xử lý
Vấn đề tỡm kiếm một khúa trờn B-Tree tổ chức ở bộ nhớ ngũai : Khi tỡm kiếm một khúa trờn B-Tree chỳng ta nạp vào bộ nhớ trong
cỏc nỳt trờnđường đi phự hợp từ nỳt gốc đến nỳt lỏ (nạp vào mảng
chứa cỏc nỳt pathnodel), và tiến hành tỡm kiếm khúa trờn cỏc nỳtđó nạp vào bộ nhớ trong nàỵ
Khi khụng tỡm thấy khúa trờn B-Tree phộp toỏn search đó nạp vào bộ nhớ trong cỏc nỳt trờn đường phự hợp tự nỳt gốc đến nỳt lỏ
(mảng pathnode[]) giỳp chỳng ta dựng mảng pathnode[]) nàyđể xử
lý việc thờm khúa vào B-Treẹ
Vấn đề thờm một khúa trờn B-Tree tổ chức ở bộ nhớ ngoài :
Khi thờm một khúa vào B-Tree trước tiờn chỳng ta gọi phộp toỏn
searchđể kiểm tra cú bị trựng khúa khụng. Nếu khụng bị trựng khúa thỡ phộp toỏn search đó nạp vàp mảng pathnode[] chứa cỏc nỳt trờn đường đi phự hợp từ nỳt gốc đến nỳt lỏ, chỳng ta dựng mảng
pathnode[] nàyđểxử lý việc thờm khúa vào B-Tree nhưmụ tả sau :
Nếu nỳt cuối của pathnode[] (cũng là nỳt lỏ của B-Tree cần thờm khúa vào) chưa đầy thỡ chỳng ta chốn khúa mới vào nỳt này, sauđú cập nhật lại nội dung của nỳt lỏ nàyở bộ nhớ ngũaị
Nếu nỳt cuối của pathnode[]đóđầy (nỳt nàyđó cú Order-1 khúa và Order nhỏnh cõy con), chỳng ta tỏch nỳt này thành hai nỳt : nỳt nửa
trỏi (gọi là nỳt current) và nỳt nửa phải (gọi là nỳt right_half). Chỳng ta phải cập nhật lại nỳt nửa trỏi (vỡ nỳt chỉ cũn lại một nửa)
và tạo mớinỳt nửa phải cho B-Treeở bộ nhớ ngoàị
Khúa chớnh giữa (median) và nỳt con right_half được chốn vào nỳt cha là nỳt ngay trước trong pathnode[]. Vấn đề được xử lý tương tự
khi chốn khúa median và nỳt con right_half vào nỳt chạ …..
Giới thiệu cỏc phộp toỏn trờn B-Tree tổ chức ở bộ nhớ ngoài :
Chỳng ta phải hiệu chỉnh, thờm/bớt một số phộp toỏn khi tổ chức B- Treeở bộ nhớ ngoàị
Gọi :
pathnode[] là mảng chứa cỏc nỳt trờnđường đi (path) từ nỳt
gốc đến nỳt lỏ trờn B-Treẹ
pathnode[i] là nỳt thứ i trong pathnode[].
Location là mảng chứa cỏc địa chỉ của cỏc nỳt trong pathnode[].
Location [i] làđịa chỉ của nỳt i trong pathnode[].
Node (loc) là nỳt trờn B-Tree tại địa chỉ loc.
Cỏc khai bỏo :
// Cac truc mot node B-Tree o bo nho ngoai struct node
{
int numtrees ; // so nhanh cay con cua node
ont key [Order-1] ; // cac khoa cua node
int Branch [Order] ; /*cac dia chi cua cac node con
cua node gia su dia chi la so nguyen */
struct node pathnode [20];/*mang chua cac node tren
duong di tu node goc den node la */
int location [20] ; /* mang chua dia chi cua cac node
tren pathnode */
Phộp toỏn makeroot (x) (gọi : ptee = makeroot (x) )
Tạo một nỳt gốc mới x cho B-Treẹ Phộp toỏn này cấp phỏt một
block bộ nhớ ngũai cho nỳt x và trả về địa chỉ của nỳt gốc mới
(Root)được cấp phỏt
Node (ađr) = pathnode[i] ; Phộp toỏn access (i,loc) :
Phộp toỏn này truy xuất nỳt ở địa chỉ loc chộp vào pathnode[i],đồng
thời chộp địa chỉ loc vao location [i] :
pathnode[i] = node (loc); location [i] = loc ;
Phộp toỏn replace (i, loc)
Khi nỳt pathnode[i] bị thay đổi chỳng ta gọi phộp toỏn này để cập
nhật lại nỳt pathnode[i] tại địa chỉ loc của B-Treeở bộ nhớ ngũai Node (location [i] = pathnode[i])
Phộp toỏn search
Tỡm khúa k trờn B-Treeở bộ nhớ ngoài
Nếu cú :
- Biến foucunrrent trả về giỏ trị TRUẸ
- Hàm search () trả về nỳt vị trớ j trong pathnode
cú chứa khúa k.
- Biến positionition trả về vị trớ của khúa k cú trờn nỳt nàỵ
Nếu khụng cú:
- Biến foucunrrent trả về giỏ trị FALSẸ
- Hàm search () trả về nỳt vị trớ cuối cựng pathnode là nỳt lỏ cú thể
thờm khúa k vàọ
- Biến positionition trả về vị trớ của khúa k nếu thờm nú vào nỳt nàỵ
int search (int k, int &positionition, int
&foucunrrent)
{
int current, i, j ;
current = Root ;/* current xuat phat tu node goc cua B-Tree*/
j = -1 ; // j la chi so tren pathnode
while (current ! = -1)
{j++ ; j++ ;
access(j,current);//nap node current vao pathnode [j]
i = nodesearch (j, k); /* tim khoa k trong pathnode [j] */
if (i < pathnode [j]. numtrees-1 && k == pathnode [j]. key [i])
{
foucunrrent = TRUE ;
positionition = i ;
return j ;
}
current = pathnode [j].Branch [i];/* current di xuong node con*/
}
/* truong hop khong co khoa k tren B-Tree, luc nay da hinh thanh mang pathnode [] chua cac node tren duong di tu node goc den node la */
poosition = i ;
return j ; // tra ve node cuoi trong pathnode
Phộp toỏn split
Tỏch nỳt đầy pathnode [current] thành hai nỳt : nỳt nửa trỏi
pathnode [current] và nỳt nửa phải right_half. Phộp toỏn này cũng cập nhật nỳt nửa trỏi và tạo mới nỳt nửa phảị
void split (int current , int extra_entry, int
extra_branch, int positionition,int &right_half, int &median)
{
// truong hop chen newky va extra_branch vao node nua phai
if (positionition > Oreder/2) {
copy (current, Oreder/2+1, Order-2, current+1 ;
/* dung
pathnode [current+1] luu node nua phai */
insnode (current+1, extra_entry, extra_branch,
positionition-Oreder/2-1) ;
// so nhanh cay con con lai cua node nua trai
pathnode[current].numtrees = Oreder/2+1 ; median = pathnode [current].key [Oreder/2] ; }
// truong hop extra_entry la median
if (positionition == Oreder/2) {
copy (current, Oreder/2, Order-2, current+1) ; /* dung
pathnode [current+1] luu node nua phai */ // so nhanh cay con con lai cua node nua trai
pathnode [current]. Numtrees = Oreder/2+1 ;
/* Dieu chinh lai node con dau tien cua node nua phai */
pathnode [current+1].Branch [0] = extra_branch
;
median = extra_entry ; }
/* truong hop chen extra_entry va extra_branch vao node nua trai */
if (positionition <Oreder/2) {
copy (current, Oreder/2, Order-2, current+1) ;
/* dung
pathnode [current+1] luu node nua phai */ //so nhanh cay con con lai cua node nua trai
pathnode[current].numtrees = Oreder/2 ;
*median = pathnode[current].key (Oreder/2-1) ;
insnode (current, extra_entry, extra_branch,
positionition) ; }
/* cap nhat lai node nua trai pathnode[current] va tao node nua phai vao B-Tree */
replace (current,location[current]) ;
right_half = makenode (current+1);
}
Phộp toỏn insert
Thờm khúa k vào vị trớ positionition của nỳt lỏ pathnode[s]
void insert (int s, int k, int positionition)
{
struct node x ;
int current, right_half, extra_entry, extra_branch,
/* Khoi dong cac tri truoc khi vao vong lap tach cac node day pathnode[current] */
current = s ;
extra_entry = k ;
extra_branch = -1 ;
positionition = positionition ;
// Vong lap tach cac node day pathnode [current]
while (current ! =0 && pathnode[current].numtrees == Order)
{
split(current,extra_entry, extra_branch,
positionition, &right_half, &median) ;
// Gan lai cac tri sau lan tach node truoc
extra_entry = median ;
extra_branch = right_half ;
positionition = nodesearch (current-1, median) ;
current--; // len node cha
}
/* Truong hop node pathnode[current] chua day va pathnode [current] khong phai la node goc */
if (pathnode[current].numtrees <Order) {
/* chen extra_entry va extra_branch tai vi tri positionition cua node pathnode [current] */
insnode (current,extra_entry, extra_branch, positionition) ;
return ; }
/* Truong hop node pathnode[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) ;
x.numtrees = 2 ; x.key [0] = mikey ;
// khoi dong dia chi cac node con cua node goc moi
for (i = 0 < i < Order; i++) x.Branch[i] = -1 ;
// Gan lai hai nhanh cay con cua node goc moi
x. Branch[0] = location [current] ; x. Branch[1] = right_half ;
Root = makeroot (x) ; }
Chương trỡnh minh họa
Chương trỡnh sau đõy tổ chức B-Tree nhưmột tập tin chứa cỏc mẩu
tin (struct), mỗi mẩu tin là một nỳt của B-Treẹ
- Mẩu tin đầu tập tin được dành riờngđể chứa header, header dựng lưu cỏc thụng tin quản lý B-Tree như Root-địa chỉ của nỳt gốc
numnodes-số nỳt cú trờn B-Tree, depth-chiều sõu của B-Tree,… - Cỏc mẩu tin sau : chức cỏc nỳt của B-Tree, mỗi nỳt cú cỏc trường
sau :
numtrees ; //số nhỏnh cõy con của nỳt
key[Order-1]; //cỏc khúa của nỳt
Branch[Order] ;// cỏcđịa chỉ của cỏc nỳt con của nỳt
Tham khảo chương trỡnh minh họa B-Tree tổ chức ở bộ nhớ ngoài sauđõy :
Chương trỡnh minh họa B-Tree tổ chức ở bộ nhớ ngoài
/* cài đặt ngụn ngữ C chuẩn */ #include <stdiọh>
#include <stdlib.h> #include <coniọh>
#include <alloc.h>
#define ORDER 5 // bac cua B-Tree
#define Ndiv2 ORDER/2 #define TRUE 1
#define FALSE 0
// Khai bao cau truc mot nut cua B-Tree o bo nho ngoai struct node
{
int numtrees; // so nhanh cay con cua nut
int key[ORDER-1]; // cac khoa cua nut
int Branch[ORDER]; // cac dia chi cua cac cay con
};
struct node pathnode[20]; /* mang chua cac nut tren
duong di tu nut goc den nut la */
int location[20]; // mang chua dia chi cua cac nut
tren pathnode
int ptree; // dia chi nut goc cua B-Tree
// Tac vu initialize: khoi dong B-Tree void initialize()
{
FILE *f;
struct node header; header.numtrees = -1; header.key[0] = 0;
f = fopen("c:\\btreẹdat", "wb");
fwrite(&header, sizeof(struct node), 1, f); fclose(f);
}
// Tac vu readheader: doc cac thong tin trong header cua tap tin B-Tree
void readheader() {
FILE *f;
struct node header;
f = fopen("c:\\btreẹdat", "rb");
fread(&header, sizeof(struct node), 1, f); // truy xuat dia chi nut goc cua B-Tree ptree = header.numtrees;
fclose(f); }
// Tac vu makeroot: tao nut goc moi x cho B-Tree int makeroot(struct node x)
{
FILE *f;
struct node temp;
if((f = fopen("c:\\btreẹdat","r+b")) == NULL) {
printf("Khong mo tap tin chua B-Tree duoc\n"); return(0);
}
// cap nhat thong tin trong header
fread(&temp, sizeof(struct node), 1, f); // cap nhat lai dia chi nut goc moi temp.numtrees = temp.key[0];
temp.key[0]++; // tang so nut co trong B-Tree
fseek(f, 0, SEEK_SET);
fwrite(&temp, sizeof(struct node), 1, f); // appecunrrent nut goc moi vao cuoi tap tin
fseek(f, 0, SEEK_END);
fwrite(&x, sizeof(struct node), 1, f); fclose(f);
return(temp.key[0]-1);
//tra ve dia chi cua nut goc moi }
/* Tac vu makenode: tao nut moi pathnode[i] cho B-Treẹ Nut moi nay la nut nua phai cua lan tach nut */
int makenode(int i) {
FILE *f;
struct node temp;
if((f = fopen("c:\\btreẹdat","r+b")) == NULL) {
printf("Khong mo tap tin chua B-Tree duoc\n"); return(0);
}
// cap nhat thong tin trong header
fread(&temp, sizeof(struct node), 1, f);
temp.key[0]++; // tang so nut co trong B-Tree fseek(f, 0, SEEK_SET);
// ghi lai header
fwrite(&temp, sizeof(struct node), 1, f); // appecunrrent nut moi vao cuoi tap tin
fseek(f, 0, SEEK_END);
fwrite(&pathnode[i], sizeof(struct node), 1, f); fclose(f);
return(temp.key[0]-1); // tra ve dia chi cua nut moi
}
/* Tac vu access: Nap nut tai dia chi loc vao pathnode[i], nap dia chi loc vao location[i] */ void access(int i, int loc)
{
FILE *f;
if((f = fopen("c:\\btreẹdat", "rb")) == NULL) {
printf("Khong mo tap tin chua B-Tree duoc\n"); return;
}
fseek(f, (loc+1)*sizeof(struct node), SEEK_SET); // Chep nut tai dia chi loc vao pathnode[i] fread(&pathnode[i], sizeof(struct node), 1, f); // Chep dia chi loc vao location[i]
location[i] = loc; fclose(f);
}
/* Tac vu replace: cap nhat lai nut pathnode[i] tai dia chi loc cua tap tin B-Tree */
void replace(int i, int loc) {
FILE *f;
if((f = fopen("c:\\btreẹdat", "r+b")) == NULL) {
printf("Khong mo tap tin chua B-Tree duoc\n\n"); return;
}
fseek(f, (loc+1)*sizeof(struct node), SEEK_SET); fwrite(&pathnode[i], sizeof(struct node), 1, f);
fclose(f); }
// Tac vu viewnodes: Xem noi dung tung nut trong tap tin B-Tree
void viewnodes() {
FILE *f;
struct node x;
int i=0, j, numnodes;
f = fopen("c:\\btreẹdat", "rb");// Doc va hien thi header // Doc va hien thi header
fread(&x, sizeof(struct node), 1, f); numnodes = x.key[0];
printf("Dia chi nut goc: %d So nut tren B-Tree: %d", x.numtrees, x.key[0]);
// hien thi thong tin cua tung nut trong B-Tree while(i < numnodes)
{
printf("\nDia chi %d:", i);
fread(&x, sizeof(struct node), 1, f); printf(" bac: %d", x.numtrees); printf(" khoa va nut con: "); for(j = 0; j < x.numtrees-1; j++) printf("%d ", x.key[j]); printf(" "); for(j = 0; j < x.numtrees; j++) printf("%d ", x.Branch[j]); i++; } fclose(f); }
/* Tac vu nodesearch: tim vi tri trong nut pathnode[p] (tra ve vi tri cua khoa bat dau lon hon hay bang k).
Truong hop k lon hon tat ca cac khoa thi tra ve
pathnode[p].numtrees-1 */ int nodesearch(int p, int k) {
int i;
for(i = 0; i < pathnode[p].numtrees-1 && pathnode[p].key[i] < k; i++);
return(i); }
/* Tac vu search: tim khoa k tren B-Tree Neu co: