PowerPoint Presentation Chương 6 Đệ quy và khử đệ quy Nội dung 1 Nhắc lại khái niệm đệ quy 2 Phân loại đệ quy 3 Đệ quy có nhớ và đệ quy quay lui 4 Khử đệ quy 2 Nhắc lại khái niệm đệ quy 3 Khái niệm đệ.
Chương 6: Đệ quy khử đệ quy Nội dung Nhắc lại khái niệm đệ quy Phân loại đệ quy Đệ quy có nhớ đệ quy quay lui Khử đệ quy Nhắc lại khái niệm đệ quy Khái niệm đệ quy Là kỹ thuật giải vấn đề vấn đề giải cách chia nhỏ chúng thành vấn đề nhỏ có dạng “A problem solving technique in which problems are solved by reducing them into smaller problems of the same form.” Ví dụ: Có sinh viên ngồi sau bạn? Có tất bạn sinh viên ngồi phía sau bạn theo “hàng dọc” lớp? Bạn nhìn người phía trước phía sau bạn Vì vậy, bạn đơn giản xoay người lại đếm Bạn phép hỏi người trước sau bạn Liệu giải vấn đề đệ quy? Ví dụ: Có sinh viên ngồi sau bạn? Người nhìn phía sau xem có người khơng Nếu khơng, người trả lời "0" Nếu có người ngồi sau, lặp lại bước chờ câu trả lời Khi người nhận câu trả lời, họ cộng thêm vào câu trả lời người ngồi sau trả lời kết cho người hỏi họ Ví dụ: Có sinh viên ngồi sau bạn? int numStudentsBehind(Student curr) { if (noOneBehind(curr)) { return 0; } else { Student personBehind = curr.getBehind(); return numStudentsBehind(personBehind) + 1; } Recursive call! } Đệ quy Cấu trúc hàm đệ quy thường có dạng sau: recursiveFunction() { if (trường hợp bản) { Tính tốn lời giải trực tiếp không dùng đệ quy } else { Chia vấn đề thành nhiều vấn đề dạng Gọi đệ quy recursiveFunction() giải vấn đề Kết hợp kết vấn đề } } Đệ quy Mọi giải thuật đệ quy cần hai trường hợp: - Trường hợp (base case): trường hợp đơn giản tính toán câu trả lời trực tiếp Các lời gọi đệ quy giảm dần tới trường hợp - Trường hợp đệ quy (recursive case): trường hợp phức tạp vấn đề mà đưa câu trả lời trực tiếp được, mơ tả thơng qua trường hợp nhỏ vấn đề Đệ quy int numStudentsBehind(Student curr) { if (noOneBehind(curr)) { Trường hợp (base case) return 0; } else { Student personBehind = curr.getBehind(); return numStudentsBehind(personBehind) + 1; } } 10 Khử đệ quy • Xét thủ tục P dạng P(X) ≡ if B(X) then D(X) else { A(X) ; P(f(X)) ; } P(X) True D(X) B(X) False A(X); P(f(X); End • Trong đó: X tập biến (một nhiều biến) P(X) thủ tục đệ quy phụ thuộc X A(X); D(X) thao tác không đệ quy f(X) hàm biến đổi X 53 Khử đệ quy • Xét q trình thực P(X) : gọi P0 lần gọi P thứ (đầu tiên) P(X) P1 lần gọi P thứ (lần 2) P(f(X)) Pi lần gọi P thứ i (lần i + 1) P(f(f( f(X) ) ( P(fi(X)) hợp i lần hàm f ) • Xét lời gọi Pi, B(fi(X)) (false) { A gọi Pi+1} (true) { D } • Giả sử P gọi n +1 lần Khi lần gọi cuối (thứ n ) Pn B(fn(X)) = true, lệnh D thực chấm dứt thao tác gọi thủ tục P 54 Khử đệ quy • Giải thuật vịng lặp: while (!B(X)) { A(X); X = f(X); } D(X); 55 Ví dụ: Tìm USCLN • Giải thuật đệ quy: • Giải thuật vòng lặp: int USCLN(int m, int n) { if (n == 0) return m; else USCLN(n, m % n); } int USCLN(int m , int n ) { int temp; while(n != 0) { // !B(x) temp = m; m = n; // X= f(X) n = m % n; // X= f(X) } return m; // D(x) } • • • • • • X (m , n) P(X) USCLN(m ,n) B(X) n == D(X) lệnh return m A(X) lệnh rỗng f(X ) f(m,n) = (n , m mod n) 56 Khử đệ quy stack • Trạng thái tiến trình xử lý giải thuật: nội dung biến lệnh cần thực • Với tiến trình xử lý giải thuật đệ quy thời điểm thực hiện, cần lưu trữ trạng thái xử lý cịn dang dở • Xét giải thuật tính giai thừa: fact(n) ≡ if(n = 0) then return else return (n * fact(n - 1)); • Sơ đồ thực hiện: fact(3) = 3*fact(2) fact(2) = 3*fact(1) fact(1) = 3*fact(0) fact(0) = 57 Khử đệ quy stack • Thủ tục đệ quy tháp Hà Nội THN(int n, char A, char B, char C) ≡ { if (n > ) then { THN(n-1, A ,C ,B); Move(A, C); THN(n-1,B,A,C);} } • Sơ đồ thực THN(3, A, B, C): 58 Khử đệ quy stack • Lời gọi đệ quy sinh lời gọi đệ quy gặp trường hợp • Ở lần gọi, phải lưu trữ thông tin trạng thái dang dở tiến trình xử lý thời điểm gọi Số trạng thái số lần gọi chưa hồn tất • Khi thực xong (hồn tất) lần gọi, cần khơi phục lại tồn thơng tin trạng thái trước gọi • Lệnh gọi cuối (ứng với trương hợp bản) hoàn tất • Cấu trúc liệu cho phép lưu trữ dãy thông tin thỏa yêu cầu cấu trúc lưu trữ thỏa mãn LIFO (Last In First Out ~ Cấu trúc Stack) 59 Khử đệ quy tuyến tính stack • Xét đệ quy tuyến tính dạng sau: P(X) ≡ if C(X) then D(X) else begin A(X) ; P(f(X)) ; B(X) ; end; đó: • X biến đơn nhiều biến • C(X) biểu thức boolean X • A(X) , B(X) , D(X): khơng đệ quy • f(X) hàm X 60 Khử đệ quy tuyến tính stack • Khử đệ quy thực P(X) stack: P(X) ≡ { create_stack(S); // tạo stack S while(not(C(X)){ A(X); push(S,X); // cất giá trị X vào stack S X := f(X); } D(X); while(not(empty(S))){ pop(S,X); // lấy liệu từ S B(X); } } 61 Ví dụ: Chuyển từ số thập phân sang nhị phân • Đệ quy: • Khử đệ quy: void binary(int m) { if (m > 0) { binary(m / 2); cout 0){ // !(C(X)) // A(X) empty stk.push(m); // push(S,X) m /= 2; // X = f(X) } // D(X) empty while(!stk.empty()){ int u = stk.top(); stk.pop(); cout