Professional Documents
Culture Documents
1
Chương 2: Hàm
2.1. Khái niệm hàm
➢Khái niệm chương trình con
➢Phân loại: hàm và thủ tục
2.2. Khai báo và sử dụng hàm
➢Khai báo và sử dụng
2.3. Phạm vi của biến
➢Biến toàn cục và địa phương
➢Phạm vi của biến
2.4. Truyền tham số
➢Truyền theo giá trị, truyền theo địa chỉ
2
Khái niệm chương trình con
• Chương trình con
– Là đoạn chương trình thực hiện một nhiệm vụ cụ thể và
được đóng gói theo cấu trúc xác định
– Được định nghĩa một lần và sử dụng lại nhiều lần.
• Vai trò
– Tổ chức một chương trình thành nhiều phần nhỏ để
tăng tính cấu trúc.
– Tiết kiệm thời gian bằng cách sử dụng chương trình
con đã có thay vì viết lại.
– Gỡ lỗi, bảo trì chương trình dễ dàng hơn
3
Hàm trong ngôn ngữ C++
• Các ngôn ngữ lập trình nói chung: 2 loại chương
trình con
– Hàm: thực hiện công việc và trả lại kết quả.
– Thủ tục: thực hiện công việc, không trả lại kết quả.
• Ngôn ngữ C++:
– Chỉ có 1 loại chương trình con là hàm (function).
– Hàm trong C++ tương đương cả hàm và thủ tục trong
các ngôn ngữ khác.
– Sử dụng kiểu void (kiểu dữ liệu không định kiểu) khi
hàm không trả về dữ liệu.
4
Ví dụ
int main(){
int i;
Gọi hàm for (i=1; i< 20; i+=2)
ra thực cout<<bp(i)<<endl;
hiện return 0;
}
5
Ví dụ
6
Cấu trúc chương trình khi viết hàm
return 0;
}
7
Cấu trúc chương trình khi viết hàm
return 0;
} Viết định
//Phần định nghĩa hàm nghĩa hàm
tại đây
8
Định nghĩa hàm
Cú pháp
Dòng tiêu đề hàm
Thân hàm
[<Các khai báo cục bộ>]
[<Các câu lệnh>]
}
9
Dòng tiêu đề hàm
10
Dòng tiêu đề hàm
Tên hàm:
• Là tên do người sử dụng tự định nghĩa
11
Dòng tiêu đề hàm
13
Dòng đầu hàm
14
Nhắc lại một số kiểu dữ liệu
double Kiểu số thực 8bytes +/- 1.7e +/- 308 (~15 digits)
15
Dòng tiêu đề hàm
• Trong C++, kiểu dữ liệu trả về của hàm có thể là
kiểu dữ liệu bất kì (kiểu dữ liệu có sẵn hoặc kiểu
dữ liệu do người dùng tự định nghĩa) nhưng không
được là kiểu dữ liệu mảng.
• Nếu kiểu dữ liệu trả về là kiểu void thì hàm không
trả về giá trị nào cả.
• Nếu không khai báo kiểu dữ liệu trả về thì chương
trình dịch của C++ sẽ ngầm hiểu rằng kiểu dữ liệu
trả về của hàm là kiểu int.
16
Thân hàm
17
Thân hàm
18
Gọi hàm
Tên_hàm (DS_tham_số_thực _sự);
Ví dụ:
N = bp(1); N = bp(3);,…
Lưu ý:
• Gọi hàm thông qua tên hàm và các tham số thực sự.
• Số lượng các tham số truyền vào phải bằng số lượng tham số hình
thức
• Kiểu của tham số truyền vào phải tương ứng với kiểu của các tham số
hình thức đã khai báo
• Nếu hàm nhận nhiều tham số thì các tham số ngăn cách nhau bởi dấu
phẩy
• Sau khi thực hiện xong, trở về vị trí mà hàm được gọi
• Gọi hàm trả về giá trị trong lệnh gán, biểu thức, printf
19
• Gọi hàm không trả về giá trị: đứng độc lập
Ví dụ
#include <iostream>
#include <cmath>
using namespace std;
float f(float x) {
return pow(x,5)+pow(x,2);
}
int main() {
float a,b,c;
cout<<"So 3 so thuc: "; cin >>a>>b>>c;
cout<<"Ket qua "<<(f(a) + f(b) + f(c))/3<<endl;
return 0;
}
22
Ví dụ 1
23
Ví dụ 2
25
Ví dụ 3
1. #include <iostream>
2. #include <cmath>
3. using namespace std;
4. int uscln(int a, int b) {
5. while (a != b){
6. if(a > b)
7. a = a - b;
8. else
9. b = b - a;
10. }
11. return a;
12. }
13. int main() {
14. int a, b;
15. char c;
16. do{
17. cout<<"Cho so nguyen a = "; cin>>a;
18. cout<<"Cho so nguyen b = "; cin>>b;
19. cout<<"Ket qua UCLN (a,b) = "<<uscln(a,b);
20. cout<<"\nBan co muon tim tiep khong(C/K)? ";
cin>>c;
21. }while (c == 'C'||c == 'c');
22. return 0;
23. } 26
Ví dụ 3
1. #include <iostream>
2. #include <cmath>
3. using namespace std;
4. int uscln(int a, int b) {
5. while (a != b){
6. if(a > b)
7. a = a - b;
8. else
9. b = b - a;
10. }
11. return a;
12. }
13. int main() {
14. int a, b;
15. char c;
16. do{
17. cout<<"Cho so nguyen a = "; cin>>a;
18. cout<<"Cho so nguyen b = "; cin>>b;
19. cout<<"Ket qua UCLN (a,b) = "<<uscln(a,b);
20. cout<<"\nBan co muon tim tiep khong(C/K)? ";
cin>>c;
21. }while (c == 'C'||c == 'c');
22. return 0;
23. } 27
Ví dụ 3
28
Ví dụ 3
29
Ví dụ 4
❖Tìm ƯSCLN của dãy số nguyên A[0], A[1],...,A[n-1]
gồm n phần tử
Ví dụ 4
1. #include <iostream> 16. cin>>n;
2. #include <cmath> 17. for(int i=0;i<n;i++)
3. using namespace std; 18. {
19. cout<<"A["<<i<<"] =
4. int uscln(int a, int b) { ";
5. while (a != b){ 20. cin>>A[i];
6. if(a > b) 21. }
7. a = a- b; 22. int r = A[0];
8. else 23. for(int i = 1; i< n;
9. b = b - a; i++)
10. } 24. r = uscln(r,A[i]);
11. return a; 25. cout<<"Ket qua USCLN
12. } cua day so: "<<r;
13. int main() { 26. return 0;
14. int A[100], n; 27. }
15. cout<<"So phan tu n =
";
31
Ví dụ 4
1. #include <iostream> 16. cin>>n;
2. #include <cmath> 17. for(int i=0;i<n;i++)
3. using namespace std; 18. {
19. cout<<"A["<<i<<"] =
4. int uscln(int a, int b) { ";
5. while (a != b){ 20. cin>>A[i];
6. if(a > b) 21. }
7. a = a- b; 22. int r = A[0];
8. else 23. for(int i = 1; i< n;
9. b = b - a; i++)
10. } 24. r = uscln(r, A[i]);
11. return a; 25. cout<<"Ket qua USCLN
12. } cua day so: "<<r;
13. int main() { 26. return 0;
14. int n, A[100]; 27. }
15. cout<<"So phan tu n =
";
32
Ví dụ 4
33
Bài tập 1
34
Chữa bài tập 1
#include<iostream>
#include<cmath>
using namespace std;
bool nguyen_to(int n) {
if (n <= 1)
return false;
for (int i = 2; i <= sqrt(n); i++)
if (n%i == 0)
return false;
return true;
}
35
Chữa bài tập 1
void thua_so_nto(int n){
for(int i=2;i<=n;i++)
while (n%i == 0 && nguyen_to(i)){
cout <<" "<< i;
n /= i;
}
}
int main(){
int n;
cout <<"Nhap vao so nguyen n: "; cin >> n;
cout<<"Phan tich n ra cac thua so nguyen to:";
thua_so_nto(n);
return 0;
}
36
Bài tập 2
Nhập vào một số nguyên n. Viết chương trình kiểm tra xem số
nguyên n nhập vào có là số đối xứng hay không?
Yêu cầu: Viết hàm bool doi_xung(int n): kiểm tra 1 số nguyên n
có phải là số đối xứng không?
37
Chữa bài tập 2
39
Các hàm có sẵn trong C++
❑ Các hàm có sẵn do các lập trình viên khác viết ra và cung
cấp cho chúng ta sử dụng
➢ Hàm chuẩn của C/C++ đi kèm với trình biên dịch
➢ Hàm do các đồng nghiệp trong cùng dự án viết cho
chúng ta
❑ Cung cấp ở dạng thư viện, chỉ việc khai báo và sử dụng
➢ Thư viện thường gồm 2 loại file:
▪ File header: chỉ chứa các khai báo hàm (.h, .hpp
hoặc không đuôi)
▪ File source: chứa phần thân hàm (.c, .cpp)
➢ Khai báo thư viện thông qua phát biểu #include
➢ Phát biểu #include phải chỉ ra file header sẽ sử dụng
▪ #include <iostream> ← tìm file trong thư mục chuẩn
▪ #include "mylib" ← tìm file trong thư mục hiện tại
40
Các hàm có sẵn trong C++
Hàm Chức năng Kiểu của Kiểu giá trị trả về Thư viện
đối số
41
Phạm vi của biến
• Phạm vi: #include<iostream>
using namespace std;
– Khối lệnh, chương trình con,
chương trình chính int i;
int binhphuong(int x){
• Biến chỉ có tác dụng trong phạm int y;
vi được khai báo y = x * x;
• Trong cùng một phạm vi các return y;
biến phải có tên khác nhau. }
Tình huống: int main(){
int y;
• Trong hai phạm vi khác nhau có hai
for (i = 0; i <= 10; i++){
biến cùng tên. Trong đó một phạm vi
này nằm trong phạm vi kia? y = binhphuong(i);
cout<<"i: "<<i<<"\t
i^2:"<< y <<endl;
}
return 0;
} 42
Phạm vi của biến
43
Phân loại biến
• Biến toàn cục:
– Biến được khai báo trong chương trình chính, được
đặt sau khai báo tệp tiêu đề.
• Biến cục bộ:
– Biến được khai báo trong khối lệnh hoặc chương trình
con.
Ghi chú:
– Hàm main() cũng là một chương trình con nhưng là
nơi chương trình được bắt đầu
– Biến khai báo trong hàm main() cũng là biến cục bộ,
chỉ có phạm vi trong hàm main().
44
Hàm không trả về giá trị
49
Hàm không trả về giá trị
#include <iostream>
using namespace std;
void trungBinh(double x, double y)
{
double s = x + y;
cout<<s/2;
}
int main () {
double x, y;
cout<<"Nhap gia tri x, y:"; cin>>x>>y;
trungBinh(x,y);
//Loi goi ham trungBinh
return 0;
}
Hàm không có tham số
void hienThi()
{
cout<<"Chao mung ban den voi mon LTNC!";
}
51
Hàm không có tham số
▪ Ví dụ:
52
Khai báo với giá trị mặc định
▪ Giá trị mặc định được sử dụng khi không truyền tham
số trong lời gọi hàm
53
Khai báo với giá trị mặc định
▪ Ví dụ:
#include <iostream>
using namespace std;
int phepChia(int a, int b = 2)
{
int r;
r=a/b;
return r;
}
int main ()
{
cout << phepChia(12);//goi ham voi gia tri mac dinh
cout << endl<<phepChia(20,4);
return 0;
}
54
Truyền tham trị, tham biến
• Truyền theo trị
– Dựa trên nguyên tắc truyền những bản sao của biến
được truyền
– Những câu lệnh thay đổi giá trị tham số hình thức sẽ
không ảnh hưởng tới biến được truyền
• Truyền theo biến
– Tham số được truyền sẽ thực sự là biến và các thao
tác sẽ thi hành trực tiếp với biến
– Những câu lệnh thay đổi giá trị tham số hình thức sẽ
ảnh hưởng tới biến được truyền
55
Ví dụ
#include <iostream>
using namespace std;
void swap(int a, int b) {
int x = a;
a = b;
b = x;
}
int main() {
int a = 5, b = 100;
cout<<"Truoc: a = "<<a<<", b = "<<b<<endl;
swap(a,b);
cout<<"Sau: a = "<<a<<", b = "<<b;
return 0;
}
Truyền tham biến
▪ Truyền bằng tham chiếu:
✓Lời gọi hàm sẽ truyền trực tiếp tham số
57
Truyền tham biến
▪ Ví dụ:
#include <iostream>
using namespace std;
void swap(int &a, int &b) {
int x = a;
a = b;
b = x;
}
int main() {
int a = 5, b = 100;
cout<<"Truoc: a = "<<a<<", b = "<<b<<endl;
swap(a,b);
cout<<"Sau: a = "<<a<<", b = "<<b;
return 0;
}
58
Truyền tham biến
▪ Ví dụ:
#include <iostream>
using namespace std;
void swap(int &a, int &b) {
int x = a;
a = b;
b = x;
}
int main() {
int a = 5, b = 100;
cout<<"Truoc: a = "<<a<<", b = "<<b<<endl;
swap(a,b);
cout<<"Sau: a = "<<a<<", b = "<<b;
return 0;
}
59
Địa chỉ của biến
#include <iostream>
using namespace std;
int main(){
int x,y;
int a[5] ={1,0,3,2,5};
cout<<"Nhap so nguyen x = "; cin>>x;
cout<<"Dia chi bo nho cua x: "<<&x;
cout<<"\nNhap so nguyen y = "; cin>>y;
cout<<"Dia chi bo nho cua y: "<<&y<<endl;
for(int i =0; i<5;i++)
cout<<"a["<<i<<"] = "<<a[i]<<"\t Dia chi bo
nho cua a["<<i<<"] = "<<&a[i]<<endl;
return 0;
}
60
Địa chỉ của biến
61
Dẫn trỏ
#include <iostream>
using namespace std;
void swap(int *pa, int *pb)
{
int x = *pa;
*pa = *pb;
*pb = x;
}
int main() {
int a = 5, b = 100;
cout<<"Truoc: a = "<<a<<", b = "<<b<<endl;
swap(a,b);
cout<<"Sau: a = "<<a<<", b = "<<b;
return 0;
}
62
Truyền theo trị và truyền theo biến
63
Ví dụ
Nhập số nguyên dương n (100>n>0)
- Viết hàm nhập dãy số n số nguyên
- Viết hàm hiển thị dãy số vừa nhập trên 1 dòng, mỗi
số cách nhau 1 dấu cách ‘ ’.
64
Ví dụ
#include <iostream> void xuat(){
#include <cmath> int i;
using namespace std; printf("In day:");
for(i = 0;i<n;i++)
int n, a[100]; //bien toan cuc printf(" %d",a[i]);
}
void nhap(){
int i;
do{
int main() {
printf("So phan tu n = "); nhap();
scanf("%d", &n); xuat();
}while(n<=0 ||n>= 100); return 0;
}
for(i = 0;i<n;i++){
printf("Phan tu thu %d: ",i+1);
scanf("%d", &a[i]);
}
}
65
Ví dụ
#include <iostream> int main() {
#include <cmath> int n, a[100];
using namespace std; do{
printf("So phan tu n = ");
void nhap(int a[100], int n){ scanf("%d", &n);
int i; }while(n<=0 ||n>= 100);
for(i=0;i<n;i++){ nhap(a,n);
printf("Phan tu thu %d: xuat(a,n);
",i+1); return 0;
scanf("%d", &a[i]); }
}
}
void xuat(int a[100], int n){
int i;
printf("In day:");
for(i=0;i<n;i++)
printf(" %d",a[i]);
}
66
Ví dụ
#include <iostream> void xuat(int a[], int
using namespace std; n){
void nhap(int a[100], int *pn){ int i;
int i; printf("In day:");
int n; for(i = 0;i<n;i++)
do{ printf(" %d",a[i]);
printf("So phan tu n = "); }
scanf("%d", &n); int main() {
}while(n<=0 || n>= 100); int N, A[100];
*pn = n; nhap(A,&N);
for(i = 0;i<n;i++){ xuat(A,N);
printf("Phan tu thu %d: ",i+1); return 0;
scanf("%d", &a[i]); }
}
}
67
Ví dụ vận dụng 1
68
Ví dụ vận dụng 1
#include <iostream> int tim_min(int b[], int n){
#include <cmath> int i, min = b[0];
using namespace std; for(i=1;i<n;i++)
void nhap(int a[100], int n){ if(min>b[i])
int i; min = b[i];
for(i=0;i<n;i++){ return min;
printf("Phan tu thu %d: ",i+1); }
scanf("%d", &a[i]); int main() {
} int n, a[100];
} do{
void xuat(int a[], int n){ printf("So phan tu n = "); scanf("%d", &n);
int i; }while(n<=0 ||n>= 100);
printf("In day:"); nhap(a,n);
for(i=0;i<n;i++) xuat(a,n);
printf(" %d",a[i]); printf("\nSo lon nhat: %d", tim_max(a,n));
} printf("\nSo nho nhat: %d",tim_min(a,n));
int tim_max(int b[], int n){ return 0;
int i, max = b[0]; }
for(i=1;i<n;i++)
if(max<b[i])
max = b[i];
return max; 69
}
Ví dụ vận dụng 2
Nhập số nguyên dương n (100>n>0)
- Viết hàm nhập dãy số n số nguyên
- Viết hàm hiển thị dãy số vừa nhập trên 1 dòng, mỗi số
cách nhau 1 dấu cách ‘ ’.
- Viết hàm kiểm tra số nguyên n có là số nguyên tố?
- Viết hàm liệt kê các số nguyên tố có trong dãy số đã nhập
- Viết hàm kiểm tra số nguyên n có là chính phương?
- Viết hàm in các số chính phương có trong dãy.
70
Ví dụ vận dụng 2
#include <iostream> void InNT(int a[], int n){
#include <cmath> int i;
using namespace std; printf("\nSo nguyen to trong day:");
void nhap(int b[], int n){ for(i=0;i<n;i++)
int i; if(nguyento(a[i]))
for(i=0;i<n;i++){
printf("Phan tu thu %d: ",i+1);
printf(" %d",a[i]);
scanf("%d", &b[i]); }
} void InCP(int a[], int n){
} printf("\nSo chinh phuong co trong day:");
void xuat(int b[], int n){ int i;
int i; for(i=0;i<n;i++)
printf("In day:");
for(i=0;i<n;i++)
if(chinhphuong(a[i]))
printf(" %d",b[i]); printf(" %d",a[i]);
} }
int nguyento(int n) { int main() {
int i; int a[100], n;
if (n <= 1) do{
return 0;
for (i = 2; i <= sqrt(n); i++)
printf("So phan tu n = "); scanf("%d", &n);
if (n%i == 0) }while(n<=0 ||n>= 100);
return 0; nhap(a,n);
return 1; xuat(a,n);
} InNT(a,n);
int chinhphuong(int n) { InCP(a,n);
if (n>=0 && sqrt(n) == floor(sqrt(n)))
return 1;
return 0;
else return 0; }
71
}
Ví dụ vận dụng 2
#include <iostream> int chinhphuong(int n) {
#include <cmath> if (n>=0 && sqrt(n) == floor(sqrt(n)))
using namespace std; return 1;
void nhap(int a[], int *pn){ else return 0;
int i; }
int n; void InNT(int a[], int n){
do{ int i;
printf("So phan tu n = "); printf("\nSo nguyen to trong day:");
scanf("%d", &n); for(i=0;i<n;i++)
}while(n<=0 || n>= 100); if(nguyento(a[i]))
*pn = n; printf(" %d",a[i]);
for(i = 0;i<n;i++){ }
printf("Phan tu thu %d: ",i+1); void InCP(int a[], int n){
scanf("%d", &a[i]); printf("\nSo chinh phuong co trong day:");
} int i;
} for(i=0;i<n;i++)
void xuat(int a[], int n){ if(chinhphuong(a[i]))
int i; printf(" %d",a[i]);
printf("In day:"); }
for(i=0;i<n;i++) int main() {
printf(" %d",a[i]); int A[100], N;
} nhap(A,&N);
int nguyento(int n) { xuat(A,N);
int i; InNT(A,N);
if (n <= 1) return 0; InCP(A,N);
for (i = 2; i <= sqrt(n); i++) return 0;
if (n%i == 0) }
return 0;
return 1; 72
}
Nạp chồng hàm
▪ Đây là một kỹ thuật cho phép sử dụng cùng một tên gọi
cho các hàm "giống nhau" (cùng mục đích) nhưng xử lý
trên các kiểu dữ liệu khác nhau hoặc trên số lượng dữ liệu
khác nhau.
▪ Ví dụ hàm sau tìm số lớn nhất trong 2 số nguyên:
int max(int a, int b)
{
return (a > b)? a:b ;
}
▪ Nếu đặt c = max(3,5) ta sẽ có c = 5. Tuy nhiên cũng tương
tự như vậy nếu đặt c = max(3.0, 5.0) chương trình sẽ bị lỗi
vì các giá trị (float) không phù hợp về kiểu (int) của đối
trong hàm max.
Trong trường hợp như vậy chúng ta phải viết hàm
mới để tính max của 2 số thực.
73
Nạp chồng hàm (tiếp)
74
Nạp chồng hàm
▪ Ví dụ:
▪ int max(int a, int b) {return (a > b)? a:b ; }
▪ float max(float a, float b) {return (a > b) ? a: b ; }
▪ char max(char a, char b) {return (a > b) ? a: b ; }
▪ long max(long a, long b) {return (a > b) ? a: b ; }
▪ double max(double a, double b) {return (a > b) ? a: b
; }
▪ Lời gọi hàm bất kỳ dạng nào: max(3,5), max(3.0,5),
max('O', 'K') đều được thực hiện.
▪ Chương trình sẽ dựa vào kiểu của các đối khi gọi để
quyết định chạy hàm nào.
75
Nạp chồng hàm
▪ Nhiều hàm có thể được nạp chồng (với cùng tên gọi giống
nhau) nếu chúng thoả các điều kiện sau:
▪ Số lượng các tham đối trong hàm là khác nhau, hoặc
▪ Kiểu của tham đối trong hàm là khác nhau.
▪ Ví dụ việc vẽ các hình: thẳng, tam giác, vuông, chữ nhật
trên màn hình là giống nhau, chúng chỉ phụ thuộc vào số
lượng các điểm nối và toạ độ của chúng. Do vậy ta có thể
khai báo và định nghĩa 4 hàm vẽ nói trên với cùng chung
tên gọi.
▪ Ví dụ:
▪ void ve( Diem A, Diem B); //Vẽ đường thẳng
▪ void ve( Diem A, Diem B, Diem C); // Vẽ tam giác
▪ void ve( Diem A, Diem B, Diem C, Diem D); //Vẽ tứ giác
76
Ví dụ
#include <iostream>
#include <cmath>
using namespace std;
int max(int a, int b) {return (a > b)? a:b; }
float max(float a, float b) {return (a > b)? a:b; }
char max(char a, char b) {return (a > b)? a:b; }
long max(long a, long b) {return (a > b)? a:b; }
double max(double a, double b) {return (a > b)? a:b; }
int main() {
cout<<"Max(3,5) = "<<max(3,5);
cout<<"\nMax(3.5,5.7) = "<<max(3.5,5.7);
cout<<"\nMax('B','E') = "<<max('B','E');
return 0;
}
77
Ví dụ
78
Ví dụ
▪ Viết các hàm tính UCLN của 2 số nguyên
int UCLN (int a, int b)
▪ Viết các hàm tính UCLN của dãy số nguyên
int UCLN(int a[], int n)
▪ Viết hàm nhập vào 1 dãy số nguyên n phần tử
void nhap()
▪ Viết hàm xuất dãy số nguyên ra màn hình
void xuat()
79
Ví dụ
#include <iostream> int UCLN(int a, int b){
#include <cmath> while (a != b){
using namespace std; if(a > b)
int A[100], N; a = a- b;
void nhap() else
{ b = b - a;
cout<<"So phan tu (<100) N = "; }
cin>>N; return a;
cout<<"Hay nhap day so:\n"; }
for(int i=0; i < N; i++){ int UCLN(int a[], int n){
cout<<"A["<<i<<"] = "; int r = a[0];
cin>>A[i]; for(int i = 1; i< n; i++)
} r = UCLN(r, a[i]);
} return r;
void xuat() }
{ int main() {
cout<<"Day vua nhap:"; nhap();
for(int i=0; i < N; i++) xuat();
cout<<" "<<A[i]; cout<<"\nUCLN cua day so la:
} "<<UCLN(A,N);
return 0;
}
80
Hàm đệ quy
▪ Khái niệm đệ quy
➢Trong thực tế, ta thường gặp những đối tượng bao gồm chính nó
hoặc được định nghĩa dưới dạng của chính nó. Ta nói đối tượng đó
được xác định một cách đệ quy.
➢Một khái niệm X gọi là định nghĩa theo đệ quy nếu trong định nghĩa
X có sử dụng ngay chính khái niệm X.
▪ Hàm đệ quy: Các hàm đệ quy được xác định phụ thuộc vào biến
nguyên không âm n theo sơ đồ sau:
➢Bước cơ sở: Xác định giá trị của hàm tại n = 0 : f(0)
➢Bước đệ quy: Cho giá trị của f(k), k<=n, đưa ra quy tắc tính giá trị
của f(n+1)
Ví dụ: f(0) = 3, f(n+1) = 2f(n)+3 với n>0
▪ Hàm đệ quy gọi lại chính nó trong quá trình thực hiện
➢Đệ quy trực tiếp: Gọi lại chính nó ngay trong thân hàm
➢Đệ quy gián tiếp: gọi lại chính nó thực hiện trong các hàm con
81
Thuật toán đệ quy
▪ Một thuật toán được gọi là đệ quy nếu nó giải bài toán bằng
cách rút gọn liên tiếp bài toán ban đầu tới bài toán tương tự
như vậy nhưng có dữ liệu đầu vào nhỏ hơn.
➢Ví dụ 1: Thuật toán tính giai thừa:
f(0) =0! =1, f(n) = n! =n*(n-1)! với n>0
➢Ví dụ 2: Thuật toán tìm dãy số Fibonacci: 0,1,1,2,3,5,8,....
F(0) = 0, F(1) = 1
F(n) = F(n - 2) + F(n - 1) với mọi n >=2
82
Thuật toán đệ quy
83
Cấu trúc chung của hàm đệ quy
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 số “nhỏ” hơn
}
84
Ví dụ
fun(5)
#include <iostream>
using namespace std; 5 * fun(4)
int fun(int n){
if(n==0)
return 1; 4 * fun(3)
else
return n*fun(n-1);
3 * fun(2)
}
int main(){
cout<<fun(5)<<endl; 2 * fun(1)
return 0;
}
1 * fun(0)
120
1
85
Ví dụ: tính n!
#include <iostream>
using namespace std;
int gt(int n){
if(n==0)
return 1;
else
return n*gt(n-1);
}
int main(){
int n;
cout<<"Cho so nguyen n = "; cin>>n;
cout<<n<<"! = "<<gt(n);
return 0;
}
86
Ví dụ tính n!
#include <iostream> cout<<"Cho so nguyen n
using namespace std; = "; cin>>n;
int gt(int n){ cout<<n<<"!="<<gt(n);
if(n==0) cout<<"\nBan co tim
return 1; tiep khong? (C/K)";
cin>>c;
else
}
return n*gt(n-1);
return 0;
}
}
int main(){
int n;
char c='C';
while(toupper(c) =='C')
{
87
Ví dụ tính n!
#include <iostream> cout<<"Cho so nguyen n
using namespace std; = "; cin>>n;
unsigned long gt(int n){ cout<<n<<"! = "<<gt(n);
if(n==0) cout<<"\nBan co tim
return 1; tiep khong? (C/K) ";
cin>>c;
else
}
return n*gt(n-1);
return 0;
}
}
int main(){
int n;
char c='C';
while(toupper(c) =='C')
{
88
Ví dụ tìm UCLN
Viết chương trình UCLN của 2 số nguyên a và b có sử dụng
đệ quy
int ucln(int a, int b) {
if (a == 0 || b == 0)
return a+b;
else
if(a>b)
return ucln(b, a%b);
else
return ucln(a, b%a);
}
89
Ví dụ tìm UCLN
90
Ví dụ tính Fibonacci
Viết chương trình tìm số Fibonacci thứ n sử dụng đệ quy:
F(0) = 0, F(1) = 1
F(n) = F(n - 2) + F(n - 1) với mọi n 2
#include <iostream>
using namespace std;
int Fibo (int n){
if(n==0) return 0;
else if(n == 1) return 1;
else
return Fibo(n-1)+ Fibo(n-2);
}
Khử đệ quy n!
Ví dụ 1: Viết chương trình tính n! không sử dụng đệ quy n!
=1.2....n
#include <iostream>
using namespace std;
int gt(int n){
int s=1;
for(int i=1; i<=n;i++)
s=s*i;
return s;
}
int main(){
int n;
cout<<"Cho so nguyen n = "; cin>>n;
cout<<n<<"! = "<<gt(n);
return 0;
}
92
Khử đệ quy n!
#include <iostream>
using namespace std;
int gt(int n){
int s=1;
for(int i=1; i<=n;i++)
s=s*i;
return s;
}
int main(){
int n;
char c='C';
while(toupper(c) =='C')
{
cout<<"Cho so nguyen n = "; cin>>n;
cout<<n<<"! = "<<gt(n);
cout<<"\nBan co tim tiep khong? (C/K) "; cin>>c;
}
return 0;
}
93
Khử đệ quy Fibonacci
Khử đệ quy Fibonacci
96
Khử đệ quy Fibonacci
97
Bài tập 1
Cho hàm f(x) được định nghĩa như sau
𝒆 𝟐𝒙+𝟏 + 𝟏 + 7 𝑘ℎ𝑖 𝑥 ≤ 2
𝑓 𝑥 =൝
𝑥 5 + 5𝑥 3 + 𝑥 + 1 𝑘ℎ𝑖 𝑥 > 2
Hãy viết chương trình thực hiện các công việc sau
• Viết chương trình con tính hàm trên
• Nhập vào từ bàn phím 2 số thực x, y, tính và đưa
ra màn hình (f(x)+f(y))2
• Đưa ra màn hình theo dòng các cặp <x, f(x)>
trong đó giá trị của x lần lượt là -5.0; -4.9; -
4.8;…..2.8; 2.9; 3.0.
Bài tập 2
• Tiền điện được tính theo số điện tiêu thụ như sau
• Dùng ít hơn 250 số: 2000đồng/số
• Dùng từ 250 đến 400 số: 3000 đồng/số
• Dùng từ 400 đến 500 số: 4000 đồng/số
• Dùng từ 500 số trở lên: 5000đ/số
• Hãy viết hàm TienDien, trả về số tiền điện phải trả với tham số
vào là số điện năng đã tiêu thụ
• Nhập vào dãy số điện sử dụng của n hộ gia đình (n<=20)
• Đưa ra màn hình số tiền điện ít nhất trong các hộ.
Ví dụ ôn lại kiến thức
▪ Nhập vào một số nguyên n. Viết chương trình kiểm tra
xem số nguyên n có là số đối xứng hay không?
▪ Đếm tất cả các số nguyên đối xứng nhỏ hơn m, với m
là số nguyên nhập từ bàn phím?
Yêu cầu:
- Viết hàm bool doi_xung(int n): kiểm tra 1 số
nguyên n có phải là số đối xứng không?
- Viết hàm int dem_dx(int m): đếm các số nguyên
đối xứng nhỏ hơn số nguyên dương m.
Gợi ý
bool doi_xung(int n)
{
int temp = n, r, s = 0;
while(temp!=0)
{
r = temp % 10;
s = s*10 + r;
temp /= 10;
}
if(s==n)
return true;
else
return false;
}
101
Gợi ý
102
Ví dụ ôn lại kiến thức
103
Ví dụ ôn lại kiến thức
104
Bài tập ôn lại kiến thức
• Nhập vào một số nguyên n. Viết chương trình phân
tích n thành các thừa số nguyên tố.
• Yêu cầu:
- Viết hàm int nguyento(int n): kiểm tra 1 số nguyên
n có phải là số nguyên tố
- Viết hàm void thua_so_nto(int n): in ra tất cả các
thừa số của n.
105
Bài tập ôn lại kiến thức
106
Bài tập ôn lại kiến thức
107
Bài tập ôn lại kiến thức
108
Bài tập ôn lại kiến thức
109
Bài tập ôn lại kiến thức
110
Hàm chung
▪ Bài toán: Viết hàm tìm giá trị lớn nhất trong hai số đầu
vào.
▪ Với các biến đầu vào thuộc kiểu double, float… phải viết
bao nhiêu hàm?
Ví dụ
Hàm chung
▪Hàm chung (hàm mẫu) được sử dụng khi kiểu dữ
liệu của các tham số và kiểu trả về không tường
minh
▪Khai báo (có thể là một trong 2 kiểu sau):
template <class tenkieu>
Dinh_nghia_ham