Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 11 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
11
Dung lượng
144,81 KB
Nội dung
Kỹ thuật lập trình nâng cao -5- PHẦN I ĐỆ QUY CHƯƠNG I KHÁI NIỆM ĐỆ QUY I MỞ ĐẦU Mô tả đệ quy Trong nhiều tình việc mô tả toán, giải thuật, kiện, vật trình, cấu trúc, đơn giản hiệu ta nhìn góc độ mang tính đệ qui Mô tả mang tính đệ qui đối tượng mô tả theo cách phân tích đối tượng thành nhiều thành phần mà số thành phần có thành phần mang tính chất đối tượng mô tả Tức mô tả đối tượng qua Các ví dụ : - Mô tả đệ quy tập số tự nhiên N : + Số số tự nhiên ( ∈ N) + Số tự nhiên số tự nhiên cộng ( n ∈ N ⇒ ( n +1 ) ∈ N ) - Mô tả đệ quy cấu trúc xâu (list) kiểu T : + Cấu trúc rỗng xâu kiểu T + Ghép nối thành phần kiểu T(nút kiểu T ) với xâu kiểu T ta có xâu kiểu T - Mô tả đệ quy gia phả : Gia phả người bao gồm mgười gia phả cha gia phả mẹ - Mô tả đê quy thủ tục chọn hoa hậu : + Chọn hoa hậu khu vực + Chọn hoa hậu hoa hậu - Mô tả đệ quy thủ tục tăng daõy a[m:n] ( daõy a[m], a[m+1], , a[n] ) phương pháp Sort_Merge (SM) : SM (a[m:n]) ≡ Merge ( SM(a[m : (n+m) div 2]) , SM (a[(n+m) div +1 : n] ) Với : SM (a[x : x]) thao tác rỗng (không làm caû ) Merge (a[x : y] , a[(y+1) : z]) thủ tục trộn dãy tăng a [x : y] , a[(y+1) : z] để dãy a[x : z] tăng - Đinh nghóa đệ quy hàm giai thừa FAC( n) = n ! 0!=1 n!=n*(n-1)! Trần Hoàng Thọ Khoa Toán - Tin Kỹ thuật lập trình nâng cao -6- Phương pháp đệ quy mạnh chổ cho phép mô tả tập lớn đối tượng số mệnh đề mô tả giải thuật phức tạp số thao tác (một chương trình đệ quy) Một mô tả đệ quy đầy đủ gồm phần : - Phần neo : mô tả trường hợp suy biến đối tượng (giải thuật) qua cấu trúc (thao tác) cụ thể xác định ví dụ: số tự nhiên, cấu trúc rỗng xâu kiểu T, ! = , SM (a[x:x]) thao tác rỗng - Phần quy nạp: mô tả đối tượng (giải thuật) trường hợp phổ biến thông qua đối tượng (giải thuật ) cách trực tiếp gián tiếp Ví dụ : n! = n * (n – 1) ! SM (a[m:n]) ≡ Merge (SM (a[m:( m+n) div 2] , SM (a[(m+n) div +1 : n]) ) Nếu mô tả phần neo đối tượng mô tả có cấu trúc lớn vô hạn, giải thuật mô tả trở thành cấu trúc lặp vô tận Các loại đệ quy Người ta phân đệ quy thành loại : Đệ quy trực tiếp, đệ quy gián tiếp - Đệ quy trực tiếp loại đệ quy mà đối tượng mô tả trực tiếp qua : A mô tả qua A, B, C, B, C, không chứa A (các ví dụ trên) - Đệ quy gián tiếp loại đệ quy mà đối tượng mô tả gián tiếp qua : A mô tả qua A1 ,A2 , , An Trong có Ai mô tả qua A Ví dụ 1: Mô tả dạng tổng quát chương trình viết NNLT Pascal : Một Chương trình Pascal gồm : a) Đầu chương trình (head) gồm: Program Tên ; b) Thân chương trình (blok) gồm : b1) Khai báo unit, định nghóa hằng, nhãn, kiểu liệu, khái báo biến b2) Định nghóa chương trình gồm : b2.1) Đầu chương trình : Procedure Tên thủ tục ( danh sách thông số hình thức ) ; Function Tên hàm ( danh sách thông số hình thức ) : Kiểu ; b2.2) Thân chương trình ( Blok ) b2.3) Dấu ‘ ; ‘ b3) Phần lệnh : lệnh ghép dạng : Begin S1 ; S2 ; ; Sn End ; c) Dấu kết thúc chương trình : ‘.’ Ví dụ : Mô tả hai dãy số {Xn},{Yn} theo luật đệ quy hổ tương sau : X0 = ; Xn = Xn-1 + Yn-1 ; Y0 = ; Yn =n2 Xn-1 + Yn-1 ; Trần Hoàng Thọ Khoa Toán - Tin Kỹ thuật lập trình nâng cao -7- II MÔ TẢ ĐỆ QUY CÁC CẤU TRÚC DỮ LIỆU Trong toán học , lập trình người ta thường sử dụng đệ quy để mô tả cấu trúc phức tạp, có tính đệ quy Bởi mô tả đệ quy không cách mô tả ngắn gọn cấu trúc phức tạp mà tạo khả để xây dựng thao tác xử lý cấu trúc phức tạp giải thuật đệ qui Một cấu trúc liệu có tính đệ quy thường gồm số thành phần liệu kiểu ghép nối theo phương thức Ví dụ 1: Mô tả đệ quy nhi phân : Cây nhi phân kiểu T : + Hoặc cấu trúc rỗng (phần neo) + Hoặc nút kiểu T (nút gốc) nhị phân kiểu T rời (cây nhị phân phải, nhị phân trái) kết hợp với Ví dụ 2: Mô tả đệ quy mảng nhiều chiều : + Mảng chiều dãy có thứ tự thành phần kiểu + Mảng n chiều mảng chiều mà thành phần có kiểu mảng n-1 chiều III MÔ TẢ ĐỆ QUY GIẢI THUẬT Giải thuật đệ quy Giải thuật đệ quy giải thuật có chứa thao tác gọi đến Giải thuật đệ quy cho phép mô tả dãy lớn thao tác số thao tác có chứa thao tác gọi lại giải thuật (gọi đệ quy) Một cách tổng quát giải thuật đệ quy biểu diễn P gồm mệnh đề S (không chứa yếu tố đệ quy ) P : P ≡ P[ S , P ] Thực thi giải thuật đệ quy dẫn tới tiến trình gọi đê quy không kết thúc khả gặp trường hợp neo, quan tâm đến điều kiện dừng giải thuật đệ quy đặt Để kiểm soát qúa trình gọi đệ quy giải thuật đệ quy P người ta thường gắn thao tác gọi P với việc kiểm tra điều kiện B xác định biến đổi qua lần gọi P , qúa trình gọi P sẻ dừng B không thỏa Mô hình tổng quát giải thuật đệ quy với quan tâm đến dừng sẻ : P ≡ if B then P[ S , P ] hoaëc P ≡ P[ S , if B then P ] Thông thường với giải thuật đệ quy P , để đảm bảo P sẻ dừng sau n lần gọi ta chọn B ( n >0 ) Mô hình giải thuật đệ quy có dạng : P(n) ≡ If ( n > ) then P[ S , P(n - 1)] ; hoaëc P(n) ≡ P[ S , if (n >0) then P(n - 1) ] ; Trần Hoàng Thọ Khoa Toán - Tin Kỹ thuật lập trình nâng cao -8- Trong ứng dụng thực tế số lần gọi đệ quy (độ sâu đệ quy) phải hữu hạn mà phải đủ nhỏ Bởi lần gọi đệ quy cần vùng nhớ vùng nhớ cũ phải trì Chương trình đệ quy a) Các hàm đệ quy Định nghóa hàm số đệ quy thường gặp toán học, điển hình hàm nguyên mô tả dãy số hồi quy Ví dụ Dãy giai thừa : { n! } ≡ ,1 , , , 24 , 120 , 720 , 5040 , Ký hiệu FAC(n ) = n ! Ta coù : + FAC(0 ) = ; ( ! = ) + FAC(n ) = n * FAC(n - ) ; ( n ! = n * (n - ) ! ) với n >= Giải thuật đệ quy tính FAC(n ) : FAC(n ) ≡ if (n = ) then return ; else return (n * FAC(n - )) ; Ví dụ Dãy số Fibonaci(FIBO) : { FIBO (n) } ≡ ,1 , , , , , 13 , 21 , 34 , 55 , 89 , 144 , 233 , 377 , + FIBO(0 ) = FIBO (1 ) = ; + FIBO(n ) = FIBO (n - ) + FIBO ( n - ) ; với n > = Giải thuật đệ quy tính FIBO ( n ) laø : FIBO(n) ≡ if ((n = ) or ( n = )) then return ; else return ( FIBO (n - 1) + FIBO (n - 2)) ; Ví dụ Dãy tổ hợp : 1 1 3 1 Cn = với n > = m Cn = với m > n > m m m Cn = Cn−−11 + Cn−1 m Giải thuật đệ quy tính Cn với n > m > : if ( m = ) then return ; else if (m > n ) then return ; m m else return ( Cn−−1 + Cn−1 ) ; Nhaän xét : Một định nghóa hàm đệ quy gồm : Trần Hoàng Thọ Khoa Toán - Tin Kỹ thuật lập trình nâng cao -9- + Một số trường hợp suy biến mà gía trị hàm biết trước tính cách đơn giản (không đệ quy ) Như : m FAC(0 ) = , FIBO(0) = FIBO(1) = , Cn = , Cn = với m > n > + Trường hợp tổng quát việc tính hàm sẻ đươc đưa tính hàm giá trị “ bé hơn” (gần với giá trị neo) đối số Như : FAC(n ) = n * FAC(n - ) ; FIBO(n) = FIBO(n -1) + FIBO( n - ) Trong tập biến hàm có nhóm mà độ lớn định độ phức tạp việc tính gía trị hàm Nhóm biến gọi nhóm biến điều khiển Gía trị biên nhóm biến điều khiển ứng với trường hợp suy biến Gía trị nhóm biến điều khiển sẻ thay đổi qua lần gọi đệ quy với xu hướng tiến đến gía trị biên ( tương ứng với trường hợp suy biến hàm ) b) Các thủ tục đệ quy Thủ tục đệ quy thủ tục có chứa lệnh gọi đến Thủ tục đệ quy thường sử dụng để mô tả thao tác cấu trúc liệu có tính đệ quy Ví dụ : Xem dãy n phần tử a[1:n] kết hợp dãy a[1:n-1] a[n] Do đo ù: - Thủ tục tìm max dãy a[1:n] ( thủ tục TMax) thực theo luật đệ qui : + Tìm max dãy a[1:n] (gọi đệ quy Tmax(a[1:n-1] ) ) + Tìm max số : Tmax(a[1:n-1]) a[n] (giải thuật không đệ quy) Tức : TMax(a[1:n]) = max(TMax(a[1:n-l]) , a[n] ) với TMax(a[m:m] = a[m] ; ( trường hợp neo ) max(x,y) = x > y ? x : y ; ( giải thuật tính max soá : if (x>y) then max(x ,y) = x else max(x ,y) = y ) - Thủ tục tính tổng phần tử ( thủ tục TSUM ) thực theo luật đệ quy : + Tìm tổng dãy a[1:n] (gọi đệ quy TSUM(a[1:n-1]) ) + Tìm tổng số : TSUM(a[1:n-1]) a[n] (giải thuật không đệ quy) Tức : TSUM(a[1:n]) = a[n] + TSUM(a[1:n-1] với TSUM(a[m:m]) = a[m] Ví dụ : Xem dãy a[m : n] kết nối hai dãy: dãy a[m:((m+n) div 2)] dãy a[(((m+n) div 2)+1) :n] Trần Hoàng Thọ Khoa Toán - Tin Kỹ thuật lập trình nâng cao - 10 - Do đo ù: - Thủ tục tìm max dãy a[1:n] ( thủ tục Tmax1) thực theo luật đệ qui : + Tìm max dãy trái a[m:((m+n) div 2)] (gọi đệ quy Tmax1(a[m:((m+n) div 2)] ) ) + Tìm max dãy phải a[(((m+n) div 2)+1) :n] (gọi đệ quy Tmax1(a[(((m+n) div 2)+1) :n] ) + Tìm max số : Tmax1(a[m:((m+n) div 2)] ) Tmax1(a[(((m+n) div 2)+1) :n] ) (giải thuật không đệ quy) Tức :Tmax1(a[m:n]) = max(Tmax1(a[m:((m+n) div 2)] ) ,Tmax1(a[(((m+n) div 2)+1) :n]) ) với Tmax1(a[m:m] = a[m] ; ( trường hợp neo ) max(x,y) = x > y ? x : y ; - Thủ tục tính tổng phần tử ( TSUM1 ) thực theo luật đệ quy : + Tìm tổng dãy trái a[m:((m+n) div 2)] (gọi đệ quy TSUM1 (a[m:((m+n) div 2)] ) ) + Tìm tổng dãy phải a[(((m+n) div 2)+1) :n] (gọi đệ quy TSUM1 (a[(((m+n) div 2)+1) :n] ) ) + Tìm tổng số : TSUM1 (a[m:((m+n) div 2)] ) TSUM1 (a[(((m+n) div 2)+1) :n] ) Tức : TSUM1 (a[m:n]) = TSUM1 (a[m:((m+n) div 2)]) + TSUM1 (a[(((m+n) div 2)+1) :n] ) với TSUM1 (a[m:m]) = a[m] Ví dụ : Cây nhị phân tìm kiếm kiểu T(BST) cấu trúc gồm : nút kiểu T kết nối với nhi phân tìm kiếm kiểu T nên : - Thụ tục quét nhi nhân tìm kiếm theo thứ tự (LNF) : + Quét trái theo thứ tự ; + Thăm nút gốc ; + Quét phải theo thứ tự ; - Thủ tục tìm kiếm giá tri αo nhị phân tìm kiếm Root : Nếu Root ≡ ∅ thực thao tác rỗng (không làm ) Con không giá trị nút gốc = αo thông báo tìm thấy dừng Còn không giá trị nút gốc < αo tìm trái Còn không tìm phải Nhận xét : Trần Hoàng Thọ Khoa Toán - Tin Kỹ thuật lập trình nâng cao - 11 - Trong thủ tục đệ qui, việc gọi đệ quy dừng lại sau hữu hạn lần gọi cần chứa điều kiện kiểm tra (một biểu thức boolean B nhóm biến ) , để điều kiện không thỏa việc gọi đệ qui kết thúc Dạng thường gặp thủ tục đệ qui : S1 ; ( không chứa yếu tố đệ qui ) if B then S2 ( phần lệnh trực tiếp , lệnh gọi đệ qui ) else Sdq ; ( phần lệnh có lệnh gọi đệ qui ) S3 ; (không có gọi đệ qui ) Mã hóa giải thuật đệ qui ngôn ngữ lập trình a) Tổng quan Không phải ngôn ngữ lập trình có mã hóa giải thuật đệ quy, số ngôn ngữ lập trình có khả tổ chức vùng nhớ kiểu stack có khả mã hóa giải thuật đệ quy Các ngôn ngữ lập trình mã hóa giải thuật đệ quy cách tổ chức chương trình đệ quy tương ứng b) Thể đệ qui NNLT PASCAL vaø C++ NN LT Pascal vaø C++ cho phép mã hóa giải thuật đệ quy cách tổ chức chương trình đê quy nhờ vào chế tạo vùng nhớ Stak phần mềm ngôn ngữ b1) Trong NNLT C++ NNLT C++ cho phép mã hóa giải thuật đệ quy cách thuận lợi nhờ vào kỹ thuật khai báo trước tiêu đề nên phân biệt hình thức việc khai báo hàm đệ quy hàm không đệ quy b2) Trong NN LT Pascal Đối với chương trình đệ quy trực tiếp hình thức khai báo giống chương trình không đệ quy Đối với chương trình đệ quy gián tiếp hình thức khai báo có thay đổi nhiều nhằm thỏa quy tắc tầm vực ngôn ngữ ( phần lệnh chương trình gọi chương trình cấp khai báo trước ) Ví dụ : Với mô hình chương trình sau : Trong phần lệnh khối A gọi đến : Trần Hoàng Thọ Khoa Toán - Tin Kỹ thuật lập trình nâng cao Program - 12 - + Gọi chương trình trực tiếp gọi B không gọi C + Gọi ( gọi đệ quy ) + Gọi chương trình cấp nhưmg phải khai báo trước gọi E không gọi D , Muốn gọi D phải khai báo trước ( khai baùo FORWARD) E A B C D Khai báo trước FORWARD Để từ thủ tục hàm A gọi đến D thủ tục hàm cấp mô tả sau A, ta cần có khai báo trước D phía trước A Khai báo gồm : tiêu đề D, với danh sách thông số D, từ khoá FORWARD Sau lúc mô tả lại D cần khai báo từ khoá PROCEDURE ( FUNCTION ) , tên D ( danh sách thông số ) , phần thân D Ví dụ : Với thủ tục gọi đệ quy hỗ tương FIRST,SECOND khai báo sau : procedure SECOND (i : integer ) ; Forward ; procedure FIRST (n : integer ; var X : real); var j, k : interger ; begin for j := to n begin writeln(‘ j = ‘, j ) ; k := n – 2* j ; SECOND( k ); end ; end ; procedure second ; begin if ( i > ) then begin writeln(‘ i= ‘, i ); FIRST( i – ) ; end ; end ; Trần Hoàng Thọ Khoa Toán - Tin Kỹ thuật lập trình nâng cao - 13 - Một số dạng giải thuật đệ quy đơn giản thường gặp a) Đệ quy tuyến tính Chương trình đệ quy tuyến tính chương trình đệ quy trực tiếp đơn giản có dạng : P ≡ { NẾU thỏa điều kiện dừng thực S ; Còn không begin { thực S* ; gọi P } } Với S , S* thao tác không đệ quy Ví dụ : Hàm FAC(n) tính số hạng n dãy n! + Dạng hàm ngôn ngữ mã giả : { Nếu n = FAC = ; /* trường hợp neo */ Còn không FAC = n*FAC(n-1) } + Dạng hàm ngôn ngữ Pascal : Function FAC(n : integer) : integer; begin if( n = ) then FAC := else FAC := n*FAC(n-1) ; end; + Dạng hàm C++ : int FAC( int n ) { if ( n == ) return ; else return ( n * FAC(n-1 )) ; } Ví dụ : Chương trình tính USCLN số dựa vào thuật toán Euclide : + Dạng hàm ngôn ngữ toán học : USCLN(m , n ) = USCLN(n , m mod n ) n ≠ USCLN(m , 0) = m + Dạng hàm ngôn ngữ mã giả : Nếu n = USCLN = m Còn không USCLN = USCLN( n , m mod n ) ; + Dạng hàm Pascal : Function USCLN(m , n : integer ) : integer ; begin if (n = ) then USCLN := m else USCLN := USCLN( n , m mod n ) ; end ; +Dạng hàm C++ : int USCLN( int m , int n ) Trần Hoàng Thọ Khoa Toán - Tin Kỹ thuật lập trình nâng cao - 14 - { if(n == ) return (m) ; else return ( USCLN( n , m mod n)) ; } b) Đệ quy nhị phân Chương trình đệ quy nhị phân chương trình đệ quy trực tiếp có dạng : P ≡ { NẾU thỏa điều kiện dừng thực S ; Còn không begin { thực S* ; gọi P ; gọi P } } Với S , S* thao tác không đệ quy Ví dụ : Hàm FIBO(n) tính số hạng n dãy FIBONACCI + Dạng haøm Pascal: Function F(n : integer) : integer; begin if( n < ) then F := else F := F(n-1) + F(n-2) end; + Dạng hàm C++ : int F(int n) { if ( n < ) return ; else return (F(n -1) + F(n -2)) ; } c) Đệ quy phi tuyến Chương trình đệ quy phi tuyến chương trình đệ quy trực tiếp mà lời gọi đệ quy thực bên vòng lặp Dạng tổng quát chương trình đệ quy phi tuyến : P ≡ { for giá tri đầu to giá trị cuối begin thực S ; if ( thỏa điều kiện dừng ) then thực S* else gọi P end ; } Với S , S* thao tác không đệ quy Ví dụ : Cho dãy { Xn } xác định theo công thức truy hoài : X0 = ; Xn = n2 XO +(n-1)2 X1 + + 2 Xn-2 + Xn-1 + Dạng hàm đệ quy tính Xn ngôn ngữ mã giả : Xn ≡ if ( n= ) then return ; Traàn Hoàng Thọ Khoa Toán - Tin Kỹ thuật lập trình naâng cao else { tg = ; for i = to n-1 return tg ; } - 15 - tg = tg + (n-i)2 Xi ; + Dạng hàm đệ quy tính Xn ngôn ngữ Pascal laø : function X( n :integer) : integer ; var i , tg : integer ; begin if ( n= ) then X := else begin tg = ; for i: = to n-1 tg : = tg + sqr(n-i) *X(i) ; X := tg ; end ; end ; + Dạng hàm đệ quy tính Xn ngôn ngữ C++ : int X( int n ) ; { if ( n == ) return ; else { int tg = ; for (int i = ; i