Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 26 trang
THÔNG TIN TÀI LIỆU
Nội dung
Cây nhị phân tìm kiếm (Binary Search Trees) Nguyễn Mạnh Hiển hiennm@tlu.edu.vn Định nghĩa • Giả thiết giá trị khác • Cây nhị phân tìm kiếm nhị phân, với nút X: − Tất giá trị trái X nhỏ X − Tất giá trị phải X lớn X Đây có phải nhị phân tìm kiếm? Các thao tác • • • • • Tìm phần tử nhỏ Tìm phần tử lớn Tìm phần tử x Chèn phần tử x Xóa phần tử x Tất thao tác có thời gian chạy trung bình O(log N) chứng minh sau Cài đặt template // T kiểu class BinarySearchTree { public: Hàm tạo, hàm hủy; Kiểm tra rỗng; Xóa rỗng cây; Tìm min, tìm max, tìm phần Chèn/xóa phần tử x; private: struct BinaryNode { }; BinaryNode * root; Các hàm trợ giúp; }; phần tử tử x; // Kiểu nút // Con trỏ tới nút gốc Kiểu nút struct BinaryNode { T elem; // Phần tử BinaryNode * left; // Con trỏ tới trái BinaryNode * right; // Con trỏ tới phải // Hàm tạo cấu trúc BinaryNode BinaryNode(T x, BinaryNode * l, BinaryNode * r) { elem = x; // Khởi tạo trường phần tử left = l; // Khởi tạo trường trỏ trái right = r; // Khởi tạo trường trỏ phải } }; Hàm tạo, hàm hủy, xóa rỗng BinarySearchTree() { root = NULL; // Ban đầu rỗng } ~BinarySearchTree() { makeEmpty(); // Xóa hết nút } void makeEmpty() { // Hàm xóa rỗng makeEmpty(root); // Gọi hàm private trợ giúp (slide sau) } bool isEmpty() { // Hàm kiểm tra rỗng return (root == NULL); } Xóa rỗng có gốc t // Hàm private trợ giúp việc xóa rỗng cây, viết theo // kiểu đệ quy void makeEmpty(BinaryNode * & t) { Có dấu & trước t gán giá trị cho t thân hàm if (t == NULL) return; // Thoát rỗng makeEmpty(t->left); // Xóa rỗng trái makeEmpty(t->right); // Xóa rỗng phải delete t; // Xóa nút gốc t = NULL; // Cây rỗng tức khơng tồn gốc } Tìm phần tử nhỏ // Hàm public T findMin() { BinaryNode * v = findMin(root); // Gọi hàm private return v->elem; // Lấy phần tử nhỏ trả } // Hàm private trợ giúp (dùng đệ quy) // Phần tử nhỏ nằm nút bên trái BinaryNode * findMin(BinaryNode if (t == NULL) // return NULL; if(t->left == NULL) // return t; return findMin(t->left); // } * t) { Cây rỗng? Nút bên trái? Tìm trái Tìm phần tử lớn // Hàm public T findMax() { BinaryNode * v = findMax(root); // Gọi hàm private return v->elem; // Lấy phần tử lớn trả } // Hàm private trợ giúp (dùng vòng lặp thay cho đệ quy) // Phần tử lớn nằm nút bên phải BinaryNode * findMax(BinaryNode * t) { if (t != NULL) while (t->right != NULL) // Chưa đến tận cùng? t = t->right; // Đi tiếp sang bên phải return t; } Chèn phần tử Trước chèn Sau chèn Cài đặt thao tác chèn // Hàm public (chèn x vào cây) void insert(T x) { insert(x, root); // Gọi hàm private } Có dấu & trước t gán giá trị // Hàm private trợ giúp (chèn x vào có gốc t) cho t thân hàm void insert(T x, BinaryNode * & t) { if (t == NULL) // Cây rỗng tạo nút t = new BinaryNode(x, NULL, NULL); else if (x < t->elem) // Nếu x nhỏ insert(x, t->left); // chèn x else if (x > t->elem) // Nếu x lớn insert(x, t->right); // chèn x else // Gặp x khơng làm ; // Câu lệnh rỗng } chứa x giá vào giá vào trị trị xét trái xét phải Xóa nút Trước xóa Sau xóa Cách xóa: Chỉ đơn giản xóa nút Xóa nút có Trước xóa Sau xóa Cách xóa: Trước xóa, cho nút cha trỏ tới nút nút bị xóa Xóa nút có hai Trước xóa Sau xóa Cách xóa: Thay nút bị xóa (2) nút nhỏ phải (3) Sau đó, xóa nút nhỏ phải (là nút nút con) Cài đặt thao tác xóa // Hàm public (xóa x khỏi cây) void remove(T x) { remove(x, root); // Gọi hàm private } // Hàm private trợ giúp (xóa x khỏi có gốc t) void remove(T x, BinaryNode * & t) { Có dấu & trước t // Xem code slide sau gán giá trị cho t thân hàm } Cài đặt thao tác xóa (tiếp) void remove(T x, BinaryNode * & t) { if (t == NULL) return; // Thoát rỗng if (x < t->elem) // Nếu x nhỏ giá trị xét remove(x, t->left); // xóa x trái else if (x > t->elem) // Nếu x lớn giá trị xét remove(x, t->right); // xóa x phải else if (t->left != NULL && t->right != NULL) { // Nút t->elem = findMin(t->right)->elem; Tìm phải remove(t->elem, t->right); đặt vào nút cần xóa } Xóa nút phải else { // Nút BinaryNode * old = t; // Giữ lại địa nút cần xóa t = (t->left != NULL) ? t->left : t->right; delete old; // Xóa Xác định (có thể NULL } Chú ý: t liên kết từ nút trường hợp nút lá) trái hay phải } cần xóa tới nút Phân tích thời gian chạy • Gọi n tổng số nút • Gọi d độ sâu trung bình nút • Thao tác xóa rỗng có thời gian chạy O(n), có nút phải xóa nút nhiêu lần • Các thao tác tìm/chèn/xóa có thời gian chạy trung bình O(d), diễn hai bước sau đây: Đi từ nút gốc tới nút v, nơi diễn thao tác, thời trung bình O(d) Xử lý nút v vài thao tác bản, tức O(1) • Tiếp theo, ta chứng minh d = O(log n), thời gian tìm/chèn/xóa trung bình O(log n) Chứng minh d = O(log n) (1) • Độ sâu trung bình nút: d = Tổng-độ-sâu-của-các-nút / Số-nút = D/n Tổng độ sâu nút (D) gọi độ dài đường bên • Hãy tính độ dài đường bên sau: 2 Chứng minh d = O(log n) (2) • Nếu trái nút gốc có i nút: D(n) = D(i) + D(n-i-1) + n-1 − D(i) độ dài đường bên trái − D(n-i-1) độ dài đường bên phải − Độ dài đường nút hai cộng thêm tính từ nút gốc toàn 11 Chứng minh d = O(log n) (3) Tính giá trị trung bình D(n): D(1) = D(n) = 1/n i=0n-1 [ D(i) + D(n-i-1) ] + n-1 = 2/n i=0n-1 D(i) + n-1 Gốc Cây có n-1 nút Gốc Cây có nút Cây có n-2 nút Gốc Cây có nút Cây có n-3 nút Chứng minh d = O(log n) D(n) = 2/n i=0n-1 D(i) + n-1 nD(n) = i=0n-1 D(i) + n(n-1) (n-1)D(n-1) = i=0n-2 D(i) + (n-1)(n-2) Lấy (1) trừ (2) theo vế, ta có: nD(n) - (n-1)D(n-1) = 2D(n-1) + 2(n-1) nD(n) = (n+1)D(n-1) + 2(n-1) D(n)/(n+1) = D(n-1)/n + 2(n-1)/[n(n+1)] < D(n-1)/n + 2/n (4) (1) (2) D(n)/(n+1) < D(n-1)/n + 2/n D(n-1)/(n) < D(n-2)/(n-1) + 2/(n-1) D(n-2)/(n-1) < D(n-3)/(n-2) + 2/(n-2) D(2)/3 < D(1)/2 + 2/2 Chứng minh d = O(log n) (5) D(n)/(n+1) < D(n-1)/n + 2/n D(n-1)/(n) < D(n-2)/(n-1) + 2/(n-1) D(n-2)/(n-1) < D(n-3)/(n-2) + 2/(n-2) D(2)/3 < D(1)/2 + 2/2 D(n)/(n+1) < D(n-1)/n + 2/n < D(n-2)/(n-1) + 2/(n-1) + 2/n < D(n-3)/(n-2) + 2/(n-2) + 2/(n-1) + 2/n < D(1)/(2) + 2/2 + + 2/(n-2) + 2/(n-1) + 2/n = i=2n 1/i Nếu ta chứng minh i=2N 1/i = O(log n) suy độ sâu trung bình nút d = D(n)/n D(n)/(n+1) = O(log n) Chứng minh d = O(log n) (6) Diện tích hình chữ nhật < diện tích 1/x i=24 1/i < ∫14 1/x dx i=2n 1/i < ∫1n 1/x dx = ln n - ln = O(log n) f(x) = 1/x 1/ 1/ 1/ 4 Bài tập Chèn giá trị sau vào nhị phân tìm kiếm rỗng: 20, 15, 19, 26, 31, 21, 14, 23, 25 Sau đó, xóa nút gốc Viết hàm nhận vào nhị phân tìm kiếm hai giá trị k1 k2, k1 k2 Hàm in tất giá trị nằm khoảng [k1; k2] ... khác • Cây nhị phân tìm kiếm nhị phân, với nút X: − Tất giá trị trái X nhỏ X − Tất giá trị phải X lớn X Đây có phải nhị phân tìm kiếm? Các thao tác • • • • • Tìm phần tử nhỏ Tìm phần tử lớn Tìm. .. O(log n) f(x) = 1/x 1/ 1/ 1/ 4 Bài tập Chèn giá trị sau vào nhị phân tìm kiếm rỗng: 20, 15, 19, 26, 31, 21, 14, 23, 25 Sau đó, xóa nút gốc Viết hàm nhận vào nhị phân tìm kiếm hai giá trị k1 k2, k1... 1/n i=0n-1 [ D(i) + D(n-i-1) ] + n-1 = 2/n i=0n-1 D(i) + n-1 Gốc Cây có n-1 nút Gốc Cây có nút Cây có n-2 nút Gốc Cây có nút Cây có n-3 nút Chứng minh d = O(log n) D(n) = 2/n i=0n-1 D(i) + n-1