Khoa công nghệ thông tin bài giảng LẬp trình cơ BẢn biên soạn



tải về 1.56 Mb.
trang18/29
Chuyển đổi dữ liệu30.08.2016
Kích1.56 Mb.
#28834
1   ...   14   15   16   17   18   19   20   21   ...   29

IV. Đệ qui

1. Khái niệm


  • Một hàm được gọi là đệ quy nếu bên trong thân hàm có lệnh gọi đến chính nó. Khi hàm gọi đệ qui đến chính nó, thì mỗi lần gọi máy sẽ tạo ra một tập các biến cục bộ mới hoàn toàn độc lập với tập các biến cục bộ đã được tạo ra trong các lần gọi trước.
    Để minh hoạ chi tiết những điều trên, ta xét một ví dụ về tính giai thừa của số nguyên dương n. Theo định nghĩa giai thừa của một số nguyên n được ký hiệu là n! và được tính như sau:

  • n!=1* 2 * 3 *…* (n-1) *n = (n-1)! *n (với 0!=1)

  • Như vậy, để tính n! ta thấy nếu n=0 thì n!=1 ngược lại thì n!=n * (n-1)!

  • Ví dụ 4.19: Để minh hoạ chi tiết những điều trên, ta xét một ví dụ về tính giai thừa của số nguyên dương n. Khi không dùng phương pháp đệ qui hàm có thể được viết như sau :

long int gt1(int n) /* Tính n! v?i n>=0*/

{

long int gtphu=1;



int i;

for (i=1;i<=n;++i)

gtphu*=i;

return gtphu;

}


  • Hàm tính n! theo phương pháp đệ qui có thể được viết như sau :

long int gt2(int n)

{

if (n==0 || n==1)



return 1;

else


return(n*gt2(n-1));

}


  • Và lời gọi hàm gt từ chương trình chính được thực hiện như sau:

int main()

{

//printf("\n 3!=%d",gt1(3));



printf("\n 3!=%d",gt2(3));

getch();


return 0;

}


  • Lần gọi đầu tiên tới hàm gt2 được thực hiện từ hàm main(). Máy sẽ tạo ra một tập các biến tự động của hàm gt2. Tập này chỉ gồm các đối n. Ta gọi đối n được tạo ra lần thứ nhất là n thứ nhất. Giá trị của tham số thực ( số 3 ) được gán cho n thứ nhất. Lúc này biến n trong thân hàm được xem là n thứ nhất. Do n thứ nhất có giá trị bằng 3 nên điều kiện trong toán tử if là sai và do đó máy sẽ lựa chọn câu lệnh else. Theo câu lệnh này, máy sẽ tính giá trị biểu thức: n*gt2(n-1) (*). Để tính biểu thức trên, máy cần gọi chính hàm gt2 vì thế lần gọi thứ hai sẽ thực hiện. Máy sẽ tạo ra đối n mới, ta gọi đó là n thứ hai. Giá trị của n-1 ở đây lại là đối của hàm , được truyền cho hàm và hiểu là n thứ hai, do vậy n thứ hai có giá trị là 2. Bây giờ, do n thứ hai vẫn chưa thoả mãn điều kiện if nên máy lại tiếp tục tính biểu thức : n*gt2(n-1) (**). Biểu thức trên lại gọi hàm gt2 lần thứ ba. Máy lại tạo ra đối n lần thứ ba và ở đây n thứ ba có giá trị bằng 1. Đối n=1 thứ ba lại được truyền cho hàm, lúc này điều kiện trong lệnh if được thoả mãn, máy đi thực hiện câu lệnh: return 1=gt2(1) (***). Bắt đầu từ đây, máy sẽ thực hiện ba lần ra khỏi hàm gt2. Lần ra khỏi hàm thứ nhất ứng với lần vào thứ ba. Kết quả là đối n thứ ba được giải phóng, hàm gt2(1) cho giá trị là 1 và máy trở về xét giá trị biểu thức
    n*gt2(1) đây là kết quả của (**) ở đây, n là n thứ hai và có giá trị bằng 2. Theo câu lệnh return, máy sẽ thực hiện lần ra khỏi hàm lần thứ hai, đối n thứ hai sẽ được giải phóng, kết quả là biểu thức trong (**) có giá trị là 2.1. Sau đó máy trở về biểu thức (*) lúc này là: n*gt2(2)=n*2*1 n lại hiểu là thứ nhất, nó có giá trị bằng 3, do vậy giá trị của biểu thức trong (*) là 3.2.1=6. Chính giá trị này được sử dụng trong câu lệnh printf của hàm main() nên kết quả in ra trên màn hình là: 3!=6.

  • Từ ví dụ trên ta thấy hàm đệ qui có đặc điểm:

  • Chương trình viết rất gọn,

  • Việc thực hiện gọi đi gọi lại hàm rất nhiều lần phụ thuộc vào độ lớn của đầu vào. Chẳng hạn trong ví dụ trên hàm được gọi n lần, mỗi lần như vậy chương trình sẽ mất thời gian để lưu giữ các thông tin của hàm gọi trước khi chuyển điều khiển đến thực hiện hàm được gọi. Mặt khác các thông tin này được lưu trữ nhiều lần trong ngăn xếp sẽ dẫn đến tràn ngăn xếp nếu n lớn.

  • Hàm đệ qui so với hàm có thể dùng vòng lặp thì đơn giản hơn, tuy nhiên với máy tính khi dùng hàm đệ qui sẽ dùng nhiều bộ nhớ trên ngăn xếp và có thể dẫn đến tràn ngăn xếp. Vì vậy khi gặp một bài toán mà có thể có cách giải lặp ( không dùng đệ qui ) thì ta nên dùng cách lặp này. Song vẫn tồn tại những bài toán chỉ có thể giải bằng đệ qui.

2. Lớp các bài toán giải được bằng đệ qui


  • Phương pháp đệ qui thường được dùng để giải các bài toán có đặc điểm:

  • Giải quyết được dễ dàng trong các trường hợp riêng gọi là trường hợp suy biến hay cơ sở, trong trường hợp này hàm được tính bình thường mà không cần gọi lại chính nó;

  • Đối với trường hợp tổng quát, bài toán có thể giải được bằng bài toán cùng dạng nhưng với tham đối khác có kích thước nhỏ hơn tham đối ban đầu. Và sau một số bước hữu hạn biến đổi cùng dạng, bài toán đưa được về trường hợp suy biến.

  • Như vậy trong trường hợp tính n! nếu n = 0 hàm cho ngay giá trị 1 mà không cần phải gọi lại chính nó, đây chính là trường hợp suy biến. Trường hợp n > 0 hàm sẽ gọi lại chính nó nhưng với n giảm 1 đơn vị. Việc gọi này được lặp lại cho đến khi n = 0.

  • Một lớp rất rộng của bài toán dạng này là các bài toán có thể định nghĩa được dưới dạng đệ qui như các bài toán lặp với số bước hữu hạn biết trước, các bài toán UCLN, tháp Hà Nội, ...

  • Cấu trúc chung của hàm đệ qui

  • Dạng thức chung của một chương trình đệ qui thường như sau:

if (trường hợp suy biến)

{

trình bày cách giải // giả định đã có cách giải



}

else // trường hợp tổng quát

{

gọi lại hàm với tham đối "bé" hơn



}

3. Các ví dụ


  • Bài toán tìm ước số chung lớn nhất (UCLN): Cho hai số nguyêna và b, tìm USCLN của hai số theo giải thuật đệ qui. Bài toán có thể được định nghĩa dưới dạng đệ qui như sau:

  • Nếu b = 0 thì UCLN = a;

  • Nếu b<>0 thì UCLN(a, b) = UCLN(b, a mod b).

  • Từ đó ta có hàm đệ qui để tính UCLN của a và b như sau.

  • Ví dụ 4.20:

int USCLN(int a, int b)

{

if (b==0)



return a;

else


return USCLN(b,a%b);

}


  • Số Fibinaci: Tính số hạng thứ n của dãy Fibonaci với giải thuật đệ qui. Dãy Fibonaci được định nghĩa như sau:

  • f(0) = f(1) = 1;

  • f(n) = f(n-1) + f(n-2) với n >=2.

    Ví dụ 4.21:

long Fib(int n)

{

long kq;



if (n==0 || n==1) kq = 1;

else kq = Fib(n-1) + Fib(n-2);

return kq;

}


  • Bài toán tháp Hà nội: Có n đĩa với kích thước to, nhỏ khác nhau. Ban đầu sắp xếp các đĩa theo trật tự kích thước vào một cọc sao cho đĩa nhỏ nhất nằm trên cùng, tức là tạo ra một dạng hình nón. Người chơi phải di chuyển toàn bộ số đĩa sang một cọc khác, tuân theo các quy tắc sau:

  • Một lần chỉ được di chuyển một đĩa;

  • Một đĩa chỉ có thể được đặt lên một đĩa lớn hơn (không nhất thiết hai đĩa này phải có kích thước liền kề, tức là đĩa nhỏ nhất có thể nằm trên đĩa lớn nhất).

  • Hình ảnh mô tả bài toán được cho như hình 4.2.



Hình 4.2 - Bài toán tháp Hanoi

  • Mô tả bài toán:

  • Đặt tên các cọc là A, B, C và qui ước A là Cọc Nguồn, B là Cọc Đích và C là Cọc Trung Gian;

  • Gọi n là tổng số đĩa;

  • Đánh số đĩa từ 1 (nhỏ nhất, trên cùng) đến n (lớn nhất, dưới cùng).

  • Thuật giải đệ qui: Để chuyển n đĩa từ cọc A sang cọc B với C là cọc trung gian:

  1. Chuyển n-1 đĩa từ A sang C. Chỉ còn lại đĩa #n trên cọc A;

  2. Chuyển đĩa #n từ A sang B;

  3. Chuyển n-1 đĩa từ C sang B cho chúng nằm trên đĩa #n

  • Ví dụ 4.22:

#include

#include

void chuyen(int sodia, char CotNguon, char CotDich, char CotTG)

{

if (sodia>0)



{

chuyen(sodia-1, CotNguon, CotTG, CotDich);

printf(" Chuyen dia %d Tu %c -> %c\n",sodia,CotNguon,CotDich);

chuyen(sodia-1, CotTG, CotDich, CotNguon);

}

}

int main()



{

char CotNguon,CotDich,CotTG;

int n;

printf("\n Hay nhap so dia: ");



scanf("%d",&n);

chuyen(n,'A','B','C');

getch();

}


  • Kết quả thực hiện ví dụ 4.22 được cho như hình 4.3.



Hình 4.3 - Kết quả thực hiện bài toán tháp Hà nội với n=4

Каталог: files -> FileMonHoc
FileMonHoc -> NGÂn hàng câu hỏi lập trình cơ BẢn nhóm câu hỏI 2 ĐIỂM
FileMonHoc -> CHƯƠng 2 giới thiệu về LÝ thuyết số
FileMonHoc -> CÁc hệ MẬt khoá CÔng khai kháC
FileMonHoc -> BỘ MÔn duyệt chủ nhiệm Bộ môn
FileMonHoc -> Khoa công nghệ thông tin cộng hòa xã HỘi chủ nghĩa việt nam
FileMonHoc -> Chủ nhiệm Bộ môn Ngô Thành Long ĐỀ CƯƠng chi tiết bài giảNG
FileMonHoc -> Chủ nhiệm Bộ môn Phan Nguyên Hải ĐỀ CƯƠng chi tiết bài giảNG
FileMonHoc -> Khoa: CÔng nghệ thông tin cộng hòa xã HỘi chủ nghĩa việt nam
FileMonHoc -> MẬt mã khóA ĐỐi xứng lý thuyết cơ bản của Shannon
FileMonHoc -> Khoa cntt cộng hòa xã HỘi chủ nghĩa việt nam

tải về 1.56 Mb.

Chia sẻ với bạn bè của bạn:
1   ...   14   15   16   17   18   19   20   21   ...   29




Cơ sở dữ liệu được bảo vệ bởi bản quyền ©hocday.com 2024
được sử dụng cho việc quản lý

    Quê hương