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ả [...]... nhất là 2 345 , số thứ hai là 543 2 Số thứ ba là: 12300 (2 345 + 543 2) = 45 23 (đúng, vì số này có các chữ số là 2, 3, 4, 5) - Nếu a = 3 thì số thứ nhất là 345 6, số thứ hai là 6 543 Nam Tỉ Phú Số thứ ba là : 12300 - ( 345 6 + 6 543 ) = 2301 (loại, vì số này có các chữ số khác với 3, 4, 5, 6) - Nếu a = 4 thì số thứ nhất là 45 67, số thứ hai là 76 54 Số thứ ba là: 12300 - (45 67 + 76 54) = 79 (loại) Vậy các số mà... tuổi Bài 94: Tìm 4 số tự nhiên liên tiếp có tích là 30 24 Bài giải: Giả sử cả 4 số đều là 10 thì tích là 10 x 10 x 10 x 10 = 10000 mà 10000 > 30 24 nên cả 4 số tự nhiên liên tiếp đó phải bé hơn 10 Vì 30 24 có tận cùng là 4 nên cả 4 số phải tìm không thể có tận cùng là 5 Do đó cả 4 số phải hoặc cùng bé hơn 5, hoặc cùng lớn hơn 5 Nếu 4 số phải tìm là 1; 2; 3; 4 thì: 1 x 2 x 3 x 4 = 24 < 30 24 (loại) Nếu 4 số... thì các số ở các ô A, B, C, D được tính hai lần Do đó để tổng 4 hàng, cột chia hết cho 4 thì tổng 4 số của 4 ô A, B, C, D phải chia cho 4 dư 2 (vì 78 chia cho 4 dư 2) Ta thấy tổng của 4 số có thể là: 10, 14, 18, 22, 26, 30, 34, 38, 42 Ta xét một vài trường hợp: 1) Tổng của 4 số bé nhất là 10 Khi đó 4 số sẽ là 1, 2, 3, 4 Do đó tổng của mỗi hàng (hay mỗi cột) là: (78 + 10) : 4 = 22 Xin nêu ra một cách... nhiều phương án khác, chẳng hạn: Bài 89: Sử dụng các con số trong mỗi biển số xe ô tô 39A 045 2, 38B 0088, 52N 8233 cùng các dấu +, -, x, : và dấu ngoặc ( ), [ ] để làm thành một phép tính đúng Nam Tỉ Phú Lời giải: * Biển số 39A 045 2 Có một số cách: (4 x 2 - 5 + 0) x 3 = 9 5x2 -4+ 3+0=9 45 : 9 - 3 - 2 = 0 (9 + 2 - 3) x 5 = 40 (4 + 5) : 9 + 2 + 0 = 3 9 : 3 - ( 5 - 4 + 2) = 0 3 - 9 : (4 + 5) - 0 = 2 9 : (4 +... vào các ô vuông sao cho tổng các số ở nét dọc (1 nét) cũng như ở nét ngang (3 nét) đều là 16 Bài giải: Tất cả các bạn đều nhận ra một phương án điền số: a = 1; b = 9; c = 5; d = 4; e = 6; g = 10; h = 3; i = 1; k = 8; l = 7 Từ đó sẽ có các phương án khác bằng cách: 1) Đổi các ô b và c 2) Đổi các ô k và l 3) Đổi các ô d và h 4) Đổi đồng thời cả 3 ô a, b, c cho 3 ô i, k, l Như vậy các bạn sẽ có 16 cách... 4 số ở mỗi hàng ngang hay tổng 5 số ở mỗi cột dọc đều là 30 Bài giải : Tổng các số từ 1 đến 14 là : ( 14 + 1) x 14 : 2 = 105 Tổng các số của 4 hàng là : 30 x 4 = 120 Tổng bốn số ở bốn ô có dấu * là : 120 - 105 = 15 Cặp bốn số ở bốn ô có dấu * là một trong các trường hợp sau : Nam Tỉ Phú 15 = 1 + 2 + 3 + 9 (1) = 1 + 2 + 4 + 8 (2) = 1 + 2 + 5 + 7 (3) = 1 + 3 + 4 + 7 (4) = 1 + 3 + 5 + 7 (5) = 2 + 3 + 4. .. 3 số cuối và chia cho 3 sẽ được 148 Bạn có biết số đứng giữa theo thứ tự trên là số nào không ? Bài giải : 38 là trung bình cộng của 5 số, nên tổng 5 số là : 138 x 5 = 690 Tổng của ba số đầu tiên là : 127 x 3 = 381 Tổng của ba số cuối cùng là : 148 x 3 = 44 4 Tổng của hai số đầu tiên là : 690 - 44 4 = 246 Số ở giữa là số đứng thứ ba, nên số ở giữa là : 381 - 246 = 135 Bài 63 : Cho bảng ô vuông gồm 10... thêm dấu phẩy vào giữa chữ số 3 và 9 của số 396 để x giảm đi 297 đơn vị Các bạn có thể thử lại Bài 48 : Điền đủ 9 chữ số : 1, 2, 3, 4, 5, 6, 7, 8, 9 vào 9 ô trống sau để được phép tính đúng : Bài giải : Bài toán chỉ có bốn cách điền như sau : 2 x 78 = 156 = 39 x 4 4 x 39 = 156 = 78 x 2 3 x 58 = 1 74 = 29 x 6 6 x 29 = 1 74 = 58 x 3 Bài 49 : Tính tuổi của ông biết: Thời niên thiếu chiếm 1/5 quãng đời của... góp chung với các bạn được chứ!), nhỏ hơn 6 và chia hết cho 3 nên Sơn có 3 quyển vở Số vở của mỗi bạn sau khi chia đều là: (6 + 3 + 3) : 3 = 4 (quyển) Như vậy Sơn được các bạn đưa thêm: 4 - 3 = 1 (quyển) Giá tiền một quyển vở là 800 đồng Nam Tỉ Phú Bài 83: Hãy điền các số từ 1 đến 9 vào các ô trống để được các phép tính đúng Bài giải: Đặt các chữ cái vào các ô trống: Theo đầu bài ta có các chữ cái khác... Thế Vinh sinh năm 144 1 Bài 71: Cu Tí chọn 4 chữ số liên tiếp nhau và dùng 4 chữ số này để viết ra 3 số gồm 4 chữ số khác nhau Biết rằng số thứ nhất viết các chữ số theo thứ tự tăng dần, số thứ hai viết các chữ số theo thứ tự giảm dần và số thứ ba viết các chữ số theo thứ tự nào đó Khi cộng ba số vừa viết thì được tổng là 12300 Bạn hãy cho biết các số mà cu Tí đã viết Bài giải : Gọi 4 số tự nhiên liên . 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. 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 đề:. 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ỏ