You are on page 1of 20

Kỹ thuật lập trình

Bài 4: Đệ quy

TS. Nguyễn Hiếu Cường


Bộ môn CNPM, Khoa CNTT
Trường ĐH GTVT
Email: cuonggt@gmail.com

Hà Nội, 2022
Nội dung chính của môn học

1. Các khái niệm cơ bản trong ngôn ngữ C

2. Hàm và tổ chức chương trình

3. Hàm và mảng

4. Đệ quy

5. Xử lý chuỗi ký tự

6. Thao tác trên các tệp tin

7. Tệp lưu cấu trúc

8. Cấp phát bộ nhớ

9. Danh sách liên kết


2
Hàm đệ quy

 Hàm đệ quy
 Là công cụ cài đặt bài toán được
định nghĩa đệ quy
 Là hàm mà bên trong thân của
hàm đó có lệnh gọi đến chính nó

 Để tránh việc lặp vô hạn, hàm


đệ quy cần phải có tính dừng
 Khi gặp một điều kiện nào đó, hàm
sẽ dừng lại việc tự gọi chính mình

3
Khái niệm đệ quy

 Đệ quy có cơ sở là quy nạp toán học

 Ví dụ:
 Tổng của n số tự nhiên đầu tiên= Tổng của (n-1) số tự nhiên đầu tiên
cộng với n:
S(n) = 1+2+3+...+n thì S(n) = S(n-1) + n
 UCLN(a, b) = UCLN(a-b, b) nếu a>b

= UCLN(a, b-a) nếu b>a


 Fibonacci(n) = Fibonacci(n-1) + Fibonacci(n-2)

4
Hoạt động của hàm đệ quy

Mỗi lần gọi đệ quy


 Tập các biến cục bộ mới được tạo ra
 Thoát khỏi hàm (theo thứ tự ngược với khi gọi hàm, bằng số lần gọi)

long Factorial(int n)
{
if (n==1)
return 1;
else
return n*Factorial(n-1);
}

5
Cách dùng đệ quy

 Dạng bài toán có thể dùng đệ quy


 Trường hợp riêng (trường hợp suy biến): Dễ dàng giải quyết

 Trường hợp tổng quát:


 Có thể quy về bài toán cùng dạng, với giá trị tham số thay đổi
 Sau một số bước gọi hàm thì dẫn đến trường hợp suy biến

 Cách xây dựng hàm đệ quy


if (trường hợp suy biến)
Tính giá trị hàm trong trường hợp riêng này
else /* trường hợp tổng quát */
{
Gọi đến hàm (đang lập) với giá trị khác của tham số
}

6
Ưu nhược điểm của đệ quy

 Ưu điểm
 Nhiều bài toán được định nghĩa đệ quy rất rõ ràng
 Tiếp cận xử lý vấn đề bằng những đoạn code gọn gàng, dễ hiểu

 Nhược điểm
 Nguy cơ cao tràn bộ nhớ
 Khắc phục: khử đệ quy (dùng vòng lặp)

7
So sánh đệ quy và lặp

 Đệ quy
 Sử dụng cấu trúc lựa chọn
Nhưng trong các lời gọi hàm đệ quy có bao hàm các yếu tố lặp
 Liên tục đưa ra các lời gọi hàm nên sẽ tốn bộ nhớ hơn
Trong trường hợp không đủ bộ nhớ  lỗi “stack overflow”
 Code thường ngắn gọn hơn, nhưng chạy chậm hơn so với dùng lặp

 Lặp
 Sử dụng các cấu trúc lặp (for, while)

 Đỡ tốn bộ nhớ hơn dùng đệ quy

8
Ví dụ

1. Nhập một dãy số và tính max dãy số đó (dùng lặp)


2. Nhập một dãy số và tính max dãy số đó (dùng đệ quy)

3. Nhập một dãy số và tính tổng của dãy số đó (dùng lặp)


4. Nhập một dãy số và tính tổng của dãy số đó (dùng đệ quy)

5. Nhập một số nguyên, xác định có phải số nguyên tố? (dùng lặp)
6. Nhập một số nguyên, xác định có phải số nguyên tố? (dùng đệ quy)

9
Các dạng đệ quy

 Đệ quy tuyến tính (Linear Recursion) là dạng cơ bản nhất


if (trường hợp suy biến)
Cách giải bài toán trong trường hợp riêng
else /* trường hợp tổng quát */
{
Gọi đến hàm (đang lập) với giá trị khác của tham số
}

 Các dạng đệ quy khác?


 Đệ quy Nhị phân
 Đệ quy Phi tuyến
 ...

10
Ví dụ (đệ quy cơ bản)

 Viết hàm đệ quy tính n!

 Viết hàm đệ quy tính S = 1 + 1*2 + 1*2*3 + … + 1*2*…*n

11
Đệ quy nhị phân

 Đóng vai trò quan trọng để cài đặt các thuật toán “chia để trị”,
duyệt cây nhị phân...

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


Cách giải bài toán trong trường hợp riêng
else /* trường hợp tổng quát */
{
Gọi đến hàm (đang lập) để giải quyết vấn đề nhỏ hơn
Gọi đến hàm (đang lập) để giải quyết vấn đề nhỏ hơn
}

12
Ví dụ

 Dãy Fibonacci được định nghĩa như sau:


 F0 = 1
 F1 = 1
 Fn = Fn-1 + Fn-2 với mọi n >=2

Hãy viết hàm đệ quy tính số Fibonacci thứ n

13
Đệ quy phi tuyến

 Việc gọi đệ quy được thực hiện bên trong vòng lặp

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


{
if (trường hợp suy biến)
Giải bài toán trong trường hợp riêng
else /* tổng quát */
{
Gọi đến hàm (đang lập) với giá trị khác của tham số
}
}

14
Ví dụ

 Hãy xác định Xn theo công thức truy hồi như sau:
X0 = 1
Xn = n2X0 + (n-1)2X1 + ... + 22Xn-2 + Xn-1 nếu n >= 1

15
Tháp Hà Nội

16
Diễn đạt bài toán dưới dạng đệ quy

Thuật toán chuyển tháp (m tầng) diễn ra như sau:


Trường hợp suy biến: m==1
 Chỉ cần chuyển tầng 1 từ (x1, y1) đến (x2, y2)

Trường hợp tổng quát: m>1


 chuyển tháp (m-1 tầng) từ (x1, y1-1) đến (x3,y3),
dùng (x2,y2) làm vị trí trung gian
 chuyển tầng (1 tầng: chính là tầng m) từ (x1, y1) đến
(x2, y2)
 chuyển tháp (m-1 tầng) từ (x3, y3) đến (x2, y2-1),
dùng (x1, y1) làm vị trí trung gian

17
Cài đặt bài toán Tháp Hà Nội
#include "stdio.h"
void cthap(int m, int x1,int y1, int x2, int y2, int x3, int y3) {
if (m<1) return;
else if(m == 1)
printf("\nChuyen tang 1 tu (%d,%d) den (%d,%d)", x1, y1, x2, y2);
else {
cthap(m-1,x1,y1-1,x3,y3,x2,y2);
printf("Chuyen tang %d tu (%d,%d) den (%d,%d)", m, x1, y1, x2, y2);
cthap(m-1,x3,y3,x2,y2-1,x1,y1);
}
}
int main() {
int m;
printf("\nSo tang: "); scanf("%d",&m);
cthap(m,10,24,30,24,50,24);
}

18
Tóm tắt

 Khái niệm đệ quy

 Cách xây dựng hàm đệ quy

 Các dạng đệ quy


 Tuyến tính

 Nhị phân

 Phi tuyến

19
Bài tập

1. Viết các hàm đệ quy tính tổng các dãy


S = 1 + 22 + 33 + ... + nn

2. Viết hàm đệ quy tìm số lớn nhất trong một mảng 1 chiều.

3. Viết hàm đệ quy tính số Fibonacci thứ n.

4. Viết hàm đệ quy tính ước số chung lớn nhất của hai số nguyên.

5. Viết hàm đệ quy tính Xn biết


X0 = 1
Xn = X0 + 2X1 + 3X2 + ... + nXn-1

6. Viết hàm đệ quy sắp xếp mảng 1 chiều.

20

You might also like