Đệ qui (Recursion) Đệ qui trong lập trình 1 Đệ qui trong thực tế (Recursion in practice) Hệ điều hành: Các thư mục Cú pháp của ngôn ngữ lập trình (Syntax of languages) Đồ họa
Bài Đệ qui (Recursion) Đệ qui lập trình Đệ qui thực tế (Recursion in practice) Hệ điều hành: Các thư mục Cú pháp ngơn ngữ lập trình (Syntax of languages) Đồ họa máy tính (Computer Graphics) Tự nhiên: cối Đệ qui lập trình Một hành trình 1000 bước việc thực hành trình bắt đầu bước thứ Làm thế để hồn thành hành trình này? Thực bước tạo hành trình có 999 bước Đệ qui lập trình Hàm (phương thức) đệ qui Đệ qui: Khi hàm gọi đến Ví dụ tính giai thừa: n! = 1· 2· 3· ··· · (n-1)· n if n = f ( n) = else n × f (n − 1) Hàm C++ // hàm đệ qui tính giai thừa int recursiveFactorial(int n) { if (n == 0) return 1; // trường hợp sở else return n * recursiveFactorial(n- 1); } Đệ qui lập trình Đệ qui tuyến tính – Đệ qui lần Kiểm tra trường hợp sở Bắt đầu việc kiểm tra trường hợp sở ( phải có trường hợp) Đây điều kiện để kết thúc đệ qui Các lời gọi đệ qui hàm phải thực hướng trình đệ qui trường hợp sở (để kết thúc đệ qui) Đệ qui lần Thực gọi đệ qui lần hàm (Có thể hàm có nhiều bước kiểm tra để định lựa chọn lời gọi đệ qui, tất trường hợp trường hợp gọi thực sự) Khi định nghĩa hàm đệ qui lần gọi đệ qui hàm phải dẫn dần trường hợp sở Đệ qui lập trình Ví dụ 1:Cộng phần tử mảng Cho mảng A có n phần tử Đệ qui lập trình Ví dụ đơn giản cho đệ qui tuyến tính Algorithm LinearSum(A, n): Input: Một mảng A có kiểu nguyên số nguyên n ≥ 1, A có n phần tử Output: Tổng n số nguyên A if n = then return A[0] else return LinearSum(A, n - 1) + A[n - 1] Ví dụ vết đệ qui: call return 15 + A[4] = 15 + = 20 LinearSum(A,5) call return 13 + A[3] = 13 + = 15 LinearSum(A,4) call return + A[2] = + = 13 LinearSum(A,3) call return + A[1] = + = LinearSum(A,2) call return A[0] = LinearSum(A,1) Đệ qui lập trình Ví dụ 2:Đảo ngược mảng Algorithm ReverseArray(A, i, j): Input: Một mảng A số i, j nguyên không âm Output: Đảo ngược mảng A từ số i đến j if i < j then Swap A[i] and A[ j] ReverseArray(A, i + 1, j - 1) return Đệ qui lập trình Định nghĩa đối cho hàm đệ qui Việc tạo đối cho hàm đệ qui quan trọng, làm cho việc xây dựng hàm đệ qui trở nên dễ dàng Trong số trường hợp ta cần bổ sung thêm cho hàm số đối, dẫn tới hàm gọi đệ qui Ví dụ, định nghĩa hàm đảo mảng sau ReverseArray(A, i, j), không định nghĩa ReverseArray(A) Đệ qui lập trình Cách tính số mũ x x =x n m n+m Nếu n chẵn x =x n n/2 x n/2 = (x n/2 ) Nếu n lẻ x = x( x n ( n −1) / 2 Đệ qui lập trình ) 10 Tính lũy thừa Hàm tính lũy thừa, p(x,n)=xn, định nghĩa đệ qui sau: if n = p ( x, n) = else x ×p ( x, n − 1) Với cách định nghĩa dẫn đến hàm tính lũy thừa có thời gian chạy O(n) (gọi đệ qui n lần) Tuy nhiên tính lũy thừa cách khác tốt cách Đệ qui lập trình 11 Đệ qui bậc Chúng ta đưa thuật tốn hiệu với thuật tốn đệ qui tuyến tính việc sử dụng thuật toán đệ qui bậc p ( x, n) = x ⋅ p ( x, (n − 1) / 2) 2 p ( x , n / ) 24 25 26 27 = = = = if n = if n > is odd if n > is even 2(4/2)2 = (24/2)2 = (22)2 = 42 = 16 21+(4/2)2 = 2(24/2)2 = 2(22)2 = 2(42) = 32 2(6/ 2)2 = (26/2)2 = (23)2 = 82 = 64 21+(6/2)2 = 2(26/2)2 = 2(23)2 = 2(82) = 128 Đệ qui lập trình 12 Hàm đệ qui bình phương Algorithm Power(x, n): Input: số x số nguyên n ≥ Output: Giá trị xn if n = then return if n lẻ then y = Power(x, (n - 1)/ 2) return x · y ·y else y = Power(x, n/ 2) return y · y Đệ qui lập trình 13 Phân tích thuật tốn đệ qui bình phương Algorithm Power(x, n): Input: số x số nguyên n ≥ Output: Giá trị xn if n = then return if n lẻ then y = Power(x, (n - 1)/ 2) return x · y · y else y = Power(x, n/ 2) return y · y Mỗi lần gọi đệ qui giá giá trị n chia đơi; ta phải gọi đệ qui logn Vậy thời gian thực thuật toán O(logn) Ở ta sử dụng biến y, quan trọng giúp ta tránh phải gọi đệ qui hai lần Đệ qui lập trình 14 Mối quan hệ log2 and log10? n log(n,2) log(n,10) 0 0.30 0.60 0.90 16 1.20 32 1.51 64 1.81 128 2.11 256 2.41 512 2.71 1024 10 3.01 Đệ qui lập trình 16 Đệ qui nhị phân (Binary Recursion) Hàm đệ qui nhị phân hàm đệ qui mà gọi đệ qui hai lần Ví dụ: Hàm vẽ thước kẻ Đệ qui lập trình 17 Hàm đệ qui lần để vẽ thước kẻ #include"conio.h" #include"iostream" using namespace std; //Hàm vẽ vạch thước void drawonetick(int ticklength, int ticklabel=-1){ cout