Môt ham đươc goi co tinh đê quy nêu trong thân cua
ham đo co lênh goi lai chinh no.
Ví dụ S(n) đươc tính thông qua S(n-1)
2 điều kiên quan trong
Tồn tai bước đê quy.
Điều kiên dừng.
47 trang |
Chia sẻ: thuychi16 | Lượt xem: 795 | Lượt tải: 1
Bạn đang xem trước 20 trang tài liệu Kĩ thuật lập trình - Chương 1: Lập trình đệ qui, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
Võ Quang Hoàng Khang
1
2 Cho S(n) = 1 + 2 + 3 + + n
=>S(10)? S(11)?
3
4Một hàm được gọi có tính đệ quy nếu trong thân của
hàm đó có lệnh gọi lại chính nó.
Ví dụ S(n) được tính thông qua S(n-1)
2 điều kiện quan trọng
Tồn tại bước đệ quy.
Điều kiện dừng.
5 B1. Tham số hoá bài toán.
B2. Phân tích trường hợp chung: đưa bài toán về
dạng bài toán cùng loại nhưng có phạm vi giải
quyết nhỏ hơn theo nghĩa dần tiến đến trường hợp
suy biến.
B3. Tìm trường hợp suy biến.
6Hàm đệ quy gồm 2 phần:
Phần cơ sở: Điều kiện để thoát khỏi đệ quy
(điểm dừng)
Phần đệ quy: gọi đến chính nó với giá trị mới
của tham số nhỏ hơn giá trị ban đầu.
Ví dụ:
1 0!
1)! -(n *n
!n
7• Công thức truy hồi tính
• Hàm đệ quy:
long GiaiThua( int n )
{
if(n==0)
return 1;
else
return GiaiThua(n-1)*n;
}
1 0!
n * 1)! -(n
!n
8• Hàm đệ quy nhập mảng 1 chiều:
void NhapMang(int a[],int n)
{
if(n>0)
{
NhapMang(a,n-1);
cin>>a[n-1];
}
}
9
10
Trong thân hàm có duy nhất 1 lời gọi hàm gọi lại chính nó
một cách tường minh.
TenHam ()
{
if (điều kiện dừng)
{
//Trả về giá trị hay kết thúc công việc
}
//Thực hiện các công việc (nếu có)
. . . TenHam ();
//Thực hiện các công việc (nếu có)
}
11
Ví dụ 1: Tính
Điều kiện dừng: S(0) = 0.
Công thức truy hồi: S(n) = S(n-1) + n.
int TongS (int n)
{
if(n==0) //điểm dừng
return 0;
return ( TongS(n-1) + n );
}
nnS 321)(
12
Ví dụ 2: Tính n!
long GiaiThua(int n)
{
if (n==0) //điểm dừng
return 1;
else
return n*GiaiThua(n-1);
}
với n=5
5n 5n 4n 3n 2n
GiaiThua(5)main()
5 4 23 1
12624120
GiaiThua(2)GiaiThua(4) GiaiThua(3)
1n
GiaiThua(1)
13
Trong thân hàm có 2 lời gọi hàm gọi lại chính nó
một cách tường minh.
TenHam ()
{
if (điều kiện dừng)
{
//Trả về giá trị hay kết thúc công việc
}
//Thực hiện các công việc (nếu có)
. . . TenHam ();
//Thực hiện các công việc (nếu có)
. . . TenHam ();
//Thực hiện các công việc (nếu có)
}
14
Ví dụ: Tính sô ́ hạng thứ n của dãy Fibonaci được định nghĩa
bởi công thức truy hồi: f0=f1=1 ;
fn = fn-1 + fn-2 ; (n>1)
Điều kiện dừng: f(0) = f(1) = 1.
long Fibonaci(int n)
{
if(n==0 || n==1)
return 1;
return Fibonaci(n-1)+ Fibonaci(n-2);
}
15
Trong thân của hàm có lời gọi hàm gọi lại chính nó được đặt bên trong vòng
lặp.
TenHam ()
{
for (int i = 1; i<=n; i++)
{
//Thực hiện một số công việc (nếu có)
if (điều kiện dừng)
{ . . .
//Trả về giá trị hay kết thúc công việc
}
else
{
//Thực hiện một số công việc (nếu có)
TenHam ();
}
}
}
16
Ví dụ: Tính số hạng thứ n của dãy {Xn} được định nghĩa như
sau: X0 =1 ;
Xn = n
2X0 + (n-1)
2X1 + + 1
2Xn-1 ; (n≥1)
Điều kiện dừng: X(0) = 1.
long TinhXn(int n)
{
if(n==0)
return 1;
long s = 0;
for (int i=1; i<=n; i++)
s = s + i * i * TinhXn(n-i);
return s;
}
17
Trong thân của hàm này có lời gọi hàm đến hàm kia và
ngược lại.
g()
f()
h()
f()
f() g()
18
TenHam2 ();
TenHam1 ()
{
//Thực hiện một sô ́ công việc (nếu có)
TenHam2 ();
//Thực hiện một sô ́ công việc (nếu có)
}
TenHam2 ()
{
//Thực hiện một sô ́ công việc (nếu có)
TenHam1 ();
//Thực hiện một sô ́ công việc (nếu có)
}
19
Ví dụ: Tính số hạng thứ n của hai dãy {Xn}, {Yn} được định nghĩa như sau:
X0 =Y0 =1 ;
Xn = Xn-1 + Yn-1; (n>0)
Yn = n
2Xn-1 + Yn-1; (n>0)
- Điều kiê ̣n dừng: X(0) = Y(0) = 1.
long TinhYn(int n);
long TinhXn (int n)
{
if(n==0)
return 1;
return TinhXn(n-1) + TinhYn(n-1);
}
//----------------------------------------------------------------------
long TinhYn (int n)
{
if(n==0)
return 1;
return n*n*TinhXn(n-1) + TinhYn(n-1);
}
Thay vì sử dụng lời giải đệ quy cho một bài toán, ta có thể
thay thế bằng lời giải không đệ quy (khử đệ quy) bằng
phương pháp lặp.
Ưu và khuyết điểm của đệ quy:
Trong lập trình HẠN CHẾ viết hàm đệ quy nếu thấy không
cần thiết.
Ưu điểm Khuyết điểm
Thuận lợi cho việc biểu diễn
bài toán
Gọn (đối với chương trình)
Có khi không được tối ưu về
thời gian
Có thể gây tốn bộ nhớ
20
Ví dụ 1: Vi trùng cứ 1 giờ lại nhân đôi. Vậy sau 5 giờ sẽ có
mấy con vi trùng nếu ban đầu có 2 con?
*Giải pháp: Gọi Vh là số vi trùng tại thời điểm h.
*Ta có:
•Vh= 2Vh-1
•V0= 2
*Đệ quy tuyến tính với V(h)=2*V(h-1) và điều kiện dừng
V(0) = 2
21
Ví dụ 2: Gửi ngân hàng 1000 USD, lãi suất 12%/năm.
Số tiền có được sau 30 năm là bao nhiêu?
Giải pháp:
•Gọi Tn là số tiền có được sau n năm.
•Ta có:
Tn= Tn-1+ 0.12Tn-1= 1.12Tn-1
V(0) = 1000
Đệ quy tuyến tính với T(n)=1.12*T(n-1) và điều kiện dừng
V(0) = 1000
22
Ví dụ 3: Bài toán tháp Hà Nội
Chuyển một chồng n đĩa với kích thước khác nhau từ cột A sang cột C
theo nguyên tắc:
23
Mỗi lần chỉ chuyển 1 đĩa.
Không được đặt đĩa lớn trên
đĩa nhỏ.
Có thể dùng cột B làm cột
trung gian B
* Tham số hoá bài toán: HaNoi (n, A, B, C)
Trong đó: n: Số đĩa.
A: Cọc nguồn
B: Cọc trung gian
C: Cọc đích
(A, B, C có kiểu ký tự)
24
Giải thuật đệ quy bài toán Tháp Hà Nội:
* Trường hợp suy biến:
Nếu n = 1 thì chuyển đĩa từ A qua C
* Trường hợp chung (n 2):
Thử với n=2: + Chuyển đĩa thứ nhất từ A sang B
+ Chuyển đĩa thứ hai từ A sang C
+ Chuyển đĩa thứ nhất từ B sang C
Tổng quát:
+ Chuyển (n -1) đĩa từ A sang B (C làm trung gian)
+ Chuyển 1 đĩa từ A sang C (B làm trung gian)
+ Chuyển (n -1) đĩa từ B sang C (A làm trung gian)
25
A B C
1 đĩa
A B C
1 đĩa
A B C
2 đĩa
A B C
2 đĩa
A B C
2 đĩa
A B C
2 đĩa
A B C
N đĩa
A B C
N đĩa
A B C
N đĩa
Giải thuật đệ quy bài toán Tháp Hà Nội:
35
void HaNoi (int n, char A, char B, char C)
{
if (n==1)
cout<<A<<“”<< C;
else
{
HaNoi(n-1, A, C, B);
HaNoi(1, A, B, C);
HaNoi(n-1, B, A, C);
}
}
Bài tập 1: Viết hàm đệ quy biểu diễn nhị phân của 1 số
nguyên n. Ví dụ: n=13 1101
36
Xuất dạng nhị phân của n:
- Nếu (n/2 > 0) thì xuất dạng nhị phân của n/2;
- Xuất (n%2);
void XuatNhiPhan(int n)
{
if (n/2>0)
XuatNhiPhan(n/2);
cout<<n%2;
}
Bài tập 2: Chuyển số giây thành giờ, phút, giây.
Ví dụ: nhập 3665 -> 1: 1: 5 giây
37
void DoiGio(int n, int &h, int &m, int &s)
{
if (n<60)
s=n;
else if (n/3600>0)
{
h=n/3600;
DoiGio(n%3600, h, m, s);
}
else
{
m=n/60;
DoiGio(n%60, h, m, s);
}
}
Bài tập 3: Tính tổng các chữ số của một số nguyên n.
Ví dụ: n=1980 =>Tổng=1+9+8+0=18
38
int Tong(int n)
{
if (n<10)
return n;
else
return n%10 + Tong(n/10);
}
+ Nếu (n<10) thì Tổng = n
+ Nếu (n>=10) thì Tổng = n%10 + Tổng các chữ số của n/10
Bài tập 4: Xuất ngược các chữ số của số nguyên n.
Ví dụ n=1980 xuất 0891
39
+ Nếu n<10 thì Xuất n
+ Nếu n>=10 thì Xuất n%10 và Xuất ngược n/10
void XuatSoNguoc(int n)
{
if (n<10)
cout<<n;
else {
cout<<n%10;
XuatSoNguoc(n/10);
}
}
Bài tập 5: Viết hàm đệ quy in đảo ngược chuỗi X
- Trường hợp chung: + In ký tự cuối cùng của chuỗi X.
+ Lấy phần chuỗi còn lại.
- Trường hợp suy biến: Nếu chuỗi rỗng thì không làm gì cả.
40
void InNguoc(char *X)
{
static int len=strlen(X);
if (len>0)
{
cout<<X[len-1];
len--;
InNguoc(X);
}
}
Bài tập 6: Viết hàm đệ quy kiểm tra xem một số có phải số
nguyên tố không
41
bool isPrime(int N)
{
if (N==1)
return true;
int static M=N-1;
if (M==1)
return true;
else if (N%M==0) return false;
else
{
M--;
isPrime(N);
}
}
Bài tập 7: In hình tam giác sau bằng cách đệ quy
42
void InSao(int n)
{
if (n>1)
InSao(n-1);
for (int i=0; i<n; i++)
cout<<"*";
cout<<endl;
}
Bài tập 8: Cho mảng a có n phần tử, tính tổng các phần tử
trong mảng bằng đệ quy
43
Điều kiện dừng: nếu n=0 thì sum(a,n)=0
Giải thuật chung: sum (a,n) = a[n-1] + sum(a, n-1), n>0
Bài tập 9: Cho mảng a có n phần tử, tìm giá trị lớn nhất
trong mảng bằng đệ quy
44
Điều kiện dừng: Mảng 1 phần tử thì trị lớn nhất là a[0]
Giải thuật chung:
Max (a,n) = a[0] , n=1
a[n-1] > Max(a, n-1)? a[n-1] : Max(a,n-1), n>1
45
1. Viết hàm đệ quy tính: xn
2. Viết hàm đệ quy đếm số lần xuất hiện của kí tự ch trong
chuỗi S.
3. Viết hàm đệ quy tính giá trị phần tử thứ k của dãy số
sau: 1 2 3 6 11 20 37 68 125 . Sau đó viết
chương trình in ra màn hình n số của dãy số trên.
46
1. Viết hàm đệ quy tính tổng S=1+2+3+4++n (với n>0)
2. Viết hàm đệ quy tính n! (với n>=0)
3. Viết hàm đệ quy tìm số hạng thứ k của dãy Fibonaci. Sau đó
viết chương trình in ra màn hình n số hạng của dãy.
4. Viết hàm đệ quy tìm ước số chung lớn nhất của 2 số nguyên
dương.
5. Viết hàm đệ quy giải quyết bài toán tháp HÀ NỘI.
6. Viết hàm đệ quy biểu diễn nhị phân của 1 số nguyên n.
7. Viết hàm đệ quy chuyển số giây thành giờ, phút, giây. Ví dụ:
nhập 3665 -> 1: 1: 5 giây
8. Viết hàm đệ quy tính tổng các chữ số của một số nguyên n.
47
9. Viết hàm đệ quy xuất ngược các chữ số của số nguyên n.
10.Viết hàm đệ quy in đảo ngược chuỗi X.
11.Viết hàm đệ quy kiểm tra xem một số n có phải số nguyên
tố không?
12.Cho mảng a có n phần tử, tính tổng các phần tử trong mảng
bằng đệ quy.
13.Cho mảng a có n phần tử, tìm giá trị lớn nhất trong mảng
bằng đệ quy.
14.Làm các bài tập trên mảng 1 chiều, sử dụng kỹ thuật đệ quy.
15.Viết hàm đệ quy in các ước số của số nguyên dương n.