Tải bản đầy đủ (.pdf) (10 trang)

bài giảng kỹ thuật lập trình chương 4 các cấu trúc dữ liệu tiên tiến nguyễn diệu hương

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (454.33 KB, 10 trang )

1
Kỹ thuậtlậptrình
Chương 4 – Các cấutrúc
dữ liệutiêntiến
1. Tìm kiếm ngoài – B-cây
(Kruse, Chương 11.3)
1.1. Định nghĩa
Lưutrữ ngoài
 Cho đến nay, ta luôn giảđịnh là có thể lưu
trữ toàn bộ
mộtcấutrúcdữ liệutrongbộ nhớ
trong
 Nếudữ liệulàquálớn không thể vừavớibộ
nhớ trong?
 Æ Sử dụng bộ nhớ ngoài
 Vấn đề: đánh giá độ phứctạpvề thờigiansử
dụng O-lớngiảđịnh mọi thao tác có thờigian
như nhau.
 Æ Không thể áp dụng với thao tác truy cập đĩa
Thờigiantruycập
 Giả sửđĩa quay vớitốc độ: 3600 RPM
 Æ một vòng quay: 1/60 giây = 16.7ms
 Trung bình cầnnửa vòng/truy cập= 8ms
 Æ 1 giây = 120 lầntruycập = 25 triệulệnh
 1 phép truy cập đĩa = 200,000 lệnh
Thờigiantruycập
 Thờigiantruycập:
 Bộ nhớ trong: μs
 Đĩacứng: ms
 Đĩamềm: s
 Đọc file:


 Đọctheotừng trang / khối(block)
 Block: 256-1024 từ
 ÆTìm kiếm ngoài: tốithiểuhóasố lầntruy
cập đĩa
2
Thờigiantruycập
 Giả sử ta sử dụng một cây AVL để lưutrữ
toàn bộ thông tin chi tiếtvề ngườiláixemáy
tạiVN (khoảng 20 triệubảnghi)
 Thu đượccâyrất cao:
h
min
= log
2
20,000,000 ~= 24
Æ mấtkhoảng 0.2s
 Giải pháp: sử dụng cây nhiều nhánh để giảm
độ cao
Cây tìm kiếm đa đường
 Cây tìm kiếmnhị phân:
 Mỗi nút có nhiềunhất2 con
 Giá trị nút cha > mọinútcủa cây con trái
< mọi nút củacâycon phải
 Cây tìm kiếm đa đường cấp m
 Mỗi nút có nhiềunhất m con
 Một nút có k con và k-1 khóa
 phân hoạch tấtcả khóa trong cây con thành k tậpcon
 (giải thích thêm: tham khảo trong Sedgewick hoặc
Drozdek)
Cây tìm kiếm 5-đường Cây đa đường cân bằng

 Mục đích:
 có chiềucaonhỏ nhất
 Điềukiện:
 Không có cây con rỗng
 Các nút lá cùng mức
 Có ít nhất m/2 con
Để xây dựng cây có chiềucaonhỏ nhất:
 Đảmbảo sao cho 0 có cây con rỗng xuấthiệntrên
B-cây: Định nghĩa
 Là cây tìm kiếmm-đường:
 Tấtcả nútlácócùngmức
 Nút giữa(trừ nút gốc) có: từđến m nút
con
 Số khóa của nút giữa= số con - 1,
 Các khóa củanútgiữaphânhoạch các khóa của
cây con như cây tìm kiếm
 Nút gốchoặc là nút lá hoặccótừ 2 đến m con
 Nút lá chứa không nhiềuhơn m -1 khóa
⎡⎤
2/m
Nên chọnm lẻ
Ví dụ: B-cây cấp5
3
Ví dụ: B-cây cấp5
1.2. Thao tác thêm
Thêm phầntử vào B-cây
1. Tìm khóa cần thêm
2. Nếu không tìm thấy, thêm khóa vào nút lá tại
vị trí kết thúc
3. Nếu nút lá đầy:

1. Tách thành 2 nút
2. Xác định nút trung vị và gửilêntrênđể chèn vào
nút cha
3. Lặplạibước2-3 với khóa trung vị cho đếnkhigặp
nút gốc
4. Nếu nút gốc đầy thì tách thành 2 nút con và
nút gốcmới
Ví dụ
 Thêm lầnlượt dãy khóa sau vào mộtB-cây
cấp5 (ban đầulàcâyrỗng):
a g f b k d h m j e s i r x c l n t u p
a g f b k d h m j e s i r x c l n t u p a g f b k d h m j e s i r x c l n t u p
4
a g f b k d h m j e s i r x c l n t u p
1.3. Cài đặtgiảithuật tìm
kiếm
Cài đặtgiảithuật
 Mô phỏng: trên bộ nhớ trong
 Sử dụng con trỏ
 Thựctế: thay con trỏ bằng địachỉ củamột
khối/trang
của đĩa
Khai báo lớpB_tree
template <class Record, int order>
class B_tree {
public: // Add public methods.
private: // data members
B_node<Record, order> *root;
// Add private auxiliary functions here.
};

LớpB_tree
template <class Record, int order>
struct B_node {
// data members:
int count;
Record data[order − 1];
B_node<Record, order> *branch[order];
// constructor:
B_node( );
};
Giảithuật tìm kiếm
template <class Record, int order>
Error_code B_tree<Record, order> ::
search_tree(Record &target)
/* Post: If there is an entry in the B-tree whose key
matches that in target, the parameter target is
replaced by the corresponding Record from the
B-tree and a code of success is returned.
Otherwise a code of not_present is returned.
Uses: recursive_search_tree */
{
return recursive_search_tree(root, target);
}
5
recursive_search_tree
template <class Record, int order>
Error_code B_tree<Record, order> :: recursive_search_tree
(B_node<Record, order> *current, Record &target)
/* Pre: current is either NULL or points to a subtree of
the B_tree.

Post: If the Key of target is not in the subtree, a code of
not_present is returned. Otherwise, a code of
success is returned and target is set to the
corresponding Record of the subtree.
Uses: recursive_search_tree recursively and
search_node */
recursive_search_tree
{
Error_code result = not_present;
int position;
if (current != NULL) {
result = search_node(current, target, position);
if (result == not_present)
result = recursive_search_tree(
current->branch[position], target);
else
target = current->data[position];
}
return result;
}
search_node
template <class Record, int order>
Error_code B_tree<Record, order> :: search_node(
B_node<Record, order> *current, const Record &target, int
&position)
/* Pre: current points to a node of a B_tree.
Post: If the Key of target is found in *current, then a code of
success is returned,
the parameter position is set to the index of target, and the
corresponding

Record is copied to target. Otherwise, a code of not_present is
returned,
and position is set to the branch index on which to continue the
search.
Uses: Methods of class Record. */
search_node
 {
 position = 0;
 while (position < current->count && target > current-
>data[position])
 position ; // Perform a sequential search through the keys.
 if (position < current->count && target == current->data[position])
 return success;
 else
 return not_present;
 }
1.3. Cài đặtgiảithuậtthêm
Thao tác thêm
 Đệ quy
 Tham số:
 Đầuvào:
 new_entry – bản ghi cần thêm
 Đầura:
 current: gốccủa cây con hiệntại
 median: bản ghi trung vị
 right_branch: con trỏ tớinútnửaphảimới
6
Khi một nút bị tách insert
template <class Record, int order>
Error_code B_tree<Record, order> :: insert(const

Record &new_entry)
/* Post: If the Key of new_entry is already in the
B_tree, a code of duplicate_error
is returned. Otherwise, a code of success is returned
and the Record
new_entry is inserted into the B-tree in such a way that
the properties
of a B-tree are preserved.
Uses: Methods of struct B_node and the auxiliary
function push_down. */
{
Record median;
B_node<Record, order> *right_branch, *new_root;
Error_code result = push_down(root, new_entry, median,
right_branch);
if (result == overflow) { // The whole tree grows in height.
// Make a brand new root for the whole B-tree.
new_root = new B_node<Record, order>;
new_root->count = 1;
new_root->data[0] = median;
new_root->branch[0] = root;
new_root->branch[1] = right_branch;
root = new_root;
result = success;
}
return result;
}
Giảithuật đệ quy thêm vào cây con
template <class Record, int order>
Error_code B_tree<Record, order> :: push_down(

B_node<Record, order> *current,
const Record &new_entry,
Record &median,
B_node<Record, order> * &right_branch)
/* Pre: current is either NULL or points to a node of a B_tree.
Post: If an entry with a Key matching that of new_entry is in the subtree to
which current points, a code of duplicate_error is returned. Otherwise,
new_entry is inserted into the subtree: If this causes the height of the
subtree to grow, a code of overflow is returned, and the Record median is
extracted to be reinserted higher in the B-tree, together with the subtree
right_branch on its right. If the height does not grow, a code of success is
returned.
Uses: Functions push_down (called recursively), search_node, split_node, and
push_in. */
{
Error_code result;
int position;
if (current == NULL) {
// Since we cannot insert in an empty tree, the recursion terminates.
median = new_entry;
right_branch = NULL;
result = overflow;
}
else { // Search the current node.
if (search_node(current, new_entry, position) == success)
result = duplicate_error;
else {
Record extra_entry;
B_node<Record, order> *extra_branch;
result = push_down(current->branch[position], new_entry,

extra_entry, extra_branch);
if (result == overflow) {
// Record extra_entry now must be added to current
if (current->count < order − 1) {
result = success;
push in(current
,
extra entry
,
extra branch
,
position)
;
Thêm khóa vào nút
7
template <class Record, int order>
void B_tree<Record, order> ::
push_in(B_node<Record, order> *current,
const Record &entry, B_node<Record, order>
*right_branch, int position)
/* Pre: current points to a node of a B_tree. The node
*current is not full and
entry belongs in *current at index position.
Post: entry has been inserted along with its right-hand
branch right_branch into
*current at index position. */
{
for (int i = current->count; i > position; i−−) {
// Shift all later data to the right.
current->data[i] = current->data[i − 1];

current->branch[i . 1] = current->branch[i];
}
current->data[position] = entry;
current->branch[position . 1] = right_branch;
current->count ;
}
Tách đôi nút
template <class Record, int order>
void B_tree<Record, order> :: split_node(
B_node<Record, order> *current,// node to be split
const Record &extra_entry, // new entry to insert
B_node<Record, order> *extra_branch, // subtree on right of extra_entr
y
int position, // index in node where extra_entry goes
B_node<Record, order> * &right_half, // new node for right half of entrie
s
Record &median) // median entry (in neither half)
/* Pre: current points to a node of a B_tree. The node *current is full, but if there
were room, the record extra_entry with its right-hand pointer extra_branch
would belong in *current at position position, 0 position < order.
Post: The node *current with extra_entry and pointer extra_branch at positio
n
position are divided into nodes *current and *right_half separated by a Recor
d
median.
Uses: Methods of struct B_node, function push_in. */
{
right_half = new B_node<Record, order>;
int mid = order/2; // The entries from mid on will go to right_half.
if (position <= mid) { // First case: extra_entry belongs in left half.

for (int i = mid; i < order − 1; i ) { // Move entries to right_half.
right_half->data[i − mid] = current->data[i];
right_half->branch[i . 1 − mid] = current->branch[i . 1];
}
current->count = mid;
right_half->count = order − 1 − mid;
push_in(current, extra_entry, extra_branch, position);
}
else { // Second case: extra_entry belongs in right half.
mid ; // Temporarily leave the median in left half.
for (int i = mid; i < order − 1; i ) { // Move entries to right_half.
right_half->data[i − mid] = current->data[i];
right_half->branch[i . 1 −
mid] = current->branch[i . 1];
}
current->count = mid;
right_half->count = order − 1 − mid;
push_in(right_half, extra_entry, extra_branch, position − mid);
}
Tách đôi nút
TH1: position == 2, order == 5
(extra_entry nằm ở nửatrái)
Chuyển các phầntử sang phải
8
Thêm extra_entry và extra_branch
Xóa median, dịch branch
TH2: position == 3, order == 5
(extra_entry thuộcnửaphải)
Chuyểnphầntử sang phải
Thêm extra_entry và extra_branch

Xóa median, dịch branch
9
1.3. Xóa nút trên B-cây
Giảithuật
 Phầntử xóa nằm ở nút lá:
 Nútlácósố phầntử > tốithiểu: xóa
 Nútlácósố phầntử = tốithiểu: xét nút lá anh em
kề
 Nếu nút kề có số phầntử > tốithiểu: chuyển1 phầntử
lên nút cha, chuyểnphầntửởnút cha xuống nút lá có
phầntử xóa.
 Nếu nút kề có số phầntử = tốithiểu: phốihợp nút lá,
nút kề và phầntử trung vị tại nút cha thành nút mới.
 Nếu nút cha bị có quá ít phầntử Æ lan truyền lên trên.
 Nút xóa nằmtại nút gốc, cây giảmchiềucao.

Phầntử xóa nằm ở nút giữa:
ÆPhầntử kế tụcnằmtạimột nút lá: thay thế phần
tử kế tụcvớiphầntử xóa => xóa tạinútlá.
Ví dụ Xóa p
Xóa d Phốihợp(tiếp)
10
Kếtquả

×