▹ Con trỏ nhanh : khởi tạo trỏ vào phần tử đầu danh sách (Head), mỗi lần lặp sẽ di chuyển sang phần tử kế tiếp của phần tử tiếp theo (2 bước). ▫ Nếu sau một số lần lặp hữu hạn mà cả h[r]
(1)(2)Ví dụ
char *pchar; short *pshort; long *plong;
pchar ++; pshort ++; plong ++;
Giả sử địa ban đầu tương ứng
trỏ 100, 200 300, kết ta có giá trị 101,
202 304 tương ứng
Nếu viết tiếp
plong += 5;
=> plong = 324
pchar -=10;
=> pchar = 91
pshort +=5;
=> pshort = 212
(3)Ví dụ
char *a;short *b; long *c;Các trỏ a, b, c trỏ tới ô nhớ 1000, 2000 3000
(4)Chú ý
++
có độ ưu tiên cao
*
nên
*p++
tương đương với
*(p++)
tức tăng địa mà
nó trỏ tới khơng phải tăng giá trị mà chứa.
*p++ = *q++
sẽ tương đương với
*p = *q;
p=p+1;
q=q+1;
(5)Ví dụ:
#include <iostream.h>
#include<conio.h>
void main ()
{
int a = 20, b = 15, *pa, *pb, temp;
pa = &a; // trỏ pa chứa địa a pb = &b; // trỏ pb chứa địa b temp = *pa;
*pa = *pb; *pb = temp;
cout << "a = " << a << endl; cout << “b = ” << b;
}
// kết xuất
màn hình
(6)Con trỏ mảng
• Truy cập phần tử mảng trỏ
6
Kiểu mảng
Kiểu trỏ
&<Tên mảng>[0]
<Tên trỏ >
&<Tên mảng> [<Vị
trí>]
<Tên trỏ> + <Vị
trí>
<Tên mảng>[<Vị
(7)Ví dụ
char ch[10], *p;
p = ch;
• p gán địa phần tử mảng ch
p = ch;
• Để tham chiếu phần tử thứ mảng ch, ta dùng cách sau:
•
ch[2]
(8)Ví dụ
#include <iostream.h>
#include <conio.h>
void main ()
{
int numbers[5], * p;
p = numbers; *p = 10;
p++; *p = 20;
p = &numbers[2]; *p = 30;
p = numbers + 3; *p = 40;
p = numbers; *(p+4) = 50;
for (int n=0; n<5; n++)
(9)Ví dụ
Numb
ers
int
Numbers[5];
p= Numbers;
int *p;
p
*p =
10;
10
p
p++; *p =
20;
20
p =
&numbers[2];
p
*p = 30;
20
p = numbers +
3;
p
p
*p = 40;
40
30 50
p
p = numbers; *(p+4) =
50;
(10)Con trỏ xâu
• Ta có
char tinhthanh[30] =“Da Lat”;
• Tương đương :
char *tinhthanh;
tinhthanh=“Da lat”;
Hoặc:
char *tinhthanh =“Da lat”;
• Ngồi thao tác xâu tương tự
như mảng
*(tinhthanh+3) = “l”
• Chú ý : với xâu thường khơng thể gán trực
tiếp dòng thứ 3
(11)Mảng trỏ
• Một ưu điểm khác mảng trỏ ta
hốn chuyển đối tượng (mảng con, cấu
trúc ) trỏ trỏ cách
hoán đổi trỏ
• Ưu điểm việc truyền tham số
hàm
• Ví dụ: Vào danh sách lớp theo họ tên, sau
đó xếp để in theo thứ tự ABC.
(12)Mảng trỏ
(13)Con trỏ trỏ tới trỏ
Ví dụ:
in ma trận vng cộng phần tử
ma trận với 10
(14)Bài tập
Vi t ch
ế
ươ
ng trình tính t ng ph n t
ổ
ầ ử
(15)int main() {
int numArray[6]; int i, sum = 0;
int *ptr = numArray;
cout << "Nhap phan tu: " << endl; for (i = 0; i < 6; i++)
cin >> *(ptr+i); ptr = numArray;
for (i = 0; i < 6; i++) { sum = sum + *ptr;
ptr++; }
cout << "Tong cac phan tu cua mang la: " << sum << endl; return(0);
(16)Bài tập
Xây d ng m t hàm tính đ dài c a chu i s
ự
ộ
ộ
ủ
ỗ ử
(17)Bài tập
Xây d ng m t hàm tính đ dài c a chu i s d ng
ự
ộ
ộ
ủ
ỗ ụ
tr
ỏ
int string_ln(char*p) /* p=&str[0] */
{
int count = 0;
while (*p != '\0') {
count++;
p++;
}
(18)Bài tập
Vi t ch
ế
ươ
ng trình nh p vào n s nguyên,
ậ
ố
th c hi n (s d ng tr ):
ự
ệ
ử ụ
ỏ
-
Tính giá trị trung bình, giá trị
max cu
ủa phầầ
n tửủ
ma
ủng
-
Sắắ
p xếắ
p phầầ
n tửủ
ma
ủng theo
(19)Ví dụ
(20)Bộ nhớ động cho mảng chiều
20
• Cách 1: Biểu diễn mảng chiều thành mảng chiều
• Gọi X mảng hai chiều có kích thước m dịng n
cột A mảng chiều tương ứng,
(21)Bộ nhớ động cho mảng chiều
21
• Cách 2: Dùng trỏ trỏ
• Ví dụ: Với mảng số ngun chiều có kích thước R * C ta khai báo sau:
int **mt;
mt = new int *[R];
int *temp = new int[R*C]; for (i=0; i< R; ++i) {
mt[i] = temp; temp += C;
}
• Để giải phóng:
(22)Bộ nhớ động cho mảng chiều
• Ví dụ khác để cấp phát động cho mảng hai chiều chứa
các số thực
float
(23)Bài tập
Vi t ch
ế
ươ
ng trình c ng hai ma tr n v i d li u m i ma tr n
ộ
ậ
ớ ữ ệ
ỗ
ậ
đ
ượ ấ
c c p phát b nh đ ng theo hai cách:
ộ
ớ ộ
1)
S d ng
ử ụ
con tr
ỏ
(24)Cộng hai ma trận với
ma trận cấp phát
động
#include <iostream.h> #include <conio.h> int main() { int M,N;int *A = NULL, *B = NULL, *C = NULL;
cout << "Nhap so dong cua ma tran:"; cin>>M;
cout << "Nhap so cot cua ma tran:"; cin>>N;
//Cầắp phát vùng nhớ cho ma trận A if(!AllocMatrix(&A,M,N))
{
cout << "Khong du bo nho! " << endl;
return 1; }
//Cầắp phát vùng nhớ cho ma trận B if(!AllocMatrix(&B,M,N))
{
cout << "Khong du bo nho! " << endl;
FreeMatrix(A); return 1; }
(25)//Cầắp phát vùng nhớ //cho ma trận C
if (!
AllocMatrix(&C,M,N)) {
cout << "Khong du
bo nho!" <<endl;
//Giaủi phóng vùng nhớ A
FreeMatrix(A);
//Giaủi phóng vùng nhớ B
FreeMatrix(B); return 1;
}
cout << "Nhap ma tran thu 1"<< endl; InputMatrix(A,M,N,'A');
cout << "Nhap ma tran thu 2"<<endl;
InputMatrix(B,M,N,'B'); clrscr();
cout<<"Ma tran thu 1"<<endl; DisplayMatrix(A,M,N);
cout<<"Ma tran thu 2"<<endl;
DisplayMatrix(B,M,N); AddMatrix(A,B,C,M,N);
cout <<"Tong hai ma tran " <<endl;
DisplayMatrix(C,M,N); //Giaủi phóng vùng nhớ A FreeMatrix(A);
//Giaủi phóng vùng nhớ B FreeMatrix(B);
//Giaủi phóng vùng nhớ C FreeMatrix(C);
(26)//Cộng hai ma trận
void AddMatrix(int *A,int *B,int*C,int M,int N) {
for(int I=0;I<M*N;++I) C[I] = A[I] + B[I];
}
//Cầắp phát vùng nhớ cho ma trận int AllocMatrix(int **A,int M,int N) {
*A = new int [M*N]; if (*A == NULL)
return 0; return 1; }
//Giaủi phóng vùng nhớ void FreeMatrix(int *A) {
(27)//Nhập giá trị cuủa ma trận
void InputMatrix(int *A,int M,int N,char Symbol) { for(int I=0;I<M;++I) for(int J=0;J<N;++J) { cout<<Symbol<<"["<<I<<"]["<<J<<"]="; cin>>A[I*N+J]; } }
//Hiếủn thị ma trận
void DisplayMatrix(int *A,int M,int N) {
for(int I=0;I<M;++I) {
for(int J=0;J<N;++J) {
(28)Mở rộng: vấn đề với cấp phát nhớ động
• Memory Leaks: Rị rỉ nhớ xảy nhớ phân bổ
không sử dụng lại không giải
(29)Mở rộng: vấn đề với cấp phát nhớ động
• Double Free: giải phóng khối nhớ hai lần
(30)Mở rộng: Con trỏ đến (Pointers to a constant)
• Một trỏ xác định để trỏ đến số
Điều có nghĩa trỏ khơng thể sử dụng để sửa
đổi giá trị mà tham chiếu.
• int num = 5;
• const int limit = 500;
• int *pi; // Pointer to an integer
• const int *pci; // Pointer to a constant integer • pi = #
(31)Mở rộng: Con trỏ (Constant pointers)
• Con trỏ khơng thể thay đổi, giá trị mà trỏ đến có
thể thay đổi
• int num;
• int *const cpi = #
• Các lệnh sau hợp lệ
(32)Truyền tham chiếu
• Hàm nhận tham số trỏ
void Swap(int *X, int *Y) {
int Temp = *X;
*X = *Y;
*Y = Temp;
}
• Để hốn đổi giá trị hai biến A B
Swap(&A, &B);
(33)Truyền tham chiếu
• Hàm nhận tham số tham chiếu
void Swap(int &X, int &Y){
int Temp = X;
X = Y;
Y = Temp;
}
• Để hoán đổi giá trị hai biến A B
Swap(A, B);
(34)Truyền tham chiếu
Khi hàm trả
về tham
chiếu,
có thể gọi hàm
ở phía bên trái
của phép
gán.
#include <iostream.h> int X = 4;
int & MyFunc(){ return X;
}
int main(){
Cout << "X=“ << X << endl;
Cout << "X=“ << MyFunc() << endl;
MyFunc() = 20; // ~X=20
Cout << "X=“ << X << endl; return 0;
}
(35)Đa hoá toán tử
•
Định nghĩa lại chức tốn tử
có sẵn
Thể phép toán cách tự nhiên hơn
•
Ví dụ: thực phép cộng, trừ số phức
Trong C: Cần phải xây dựng hàm
AddSP(),
TruSP()
Không thể phép cộng trừ cho
biểu thức như:
a=b+c-d+e+f-h-k
(36)#include <stdio.h> struct SP {
double real; double img; };
SP SetSP(double real, double img); SP AddSP(SP C1,SP C2);
SP SubSP(SP C1,SP C2); void DisplaySP(SP C); int main(void) {
SP C1,C2,C3,C4;
C1 = SetSP(1.0,2.0); C2 = SetSP(-3.0,4.0);
cout << "\nSo phuc thu nhat:"; DisplaySP(C1); cout << "\nSo phuc thu hai:"; DisplaySP(C2); C3 = AddSP(C1,C2);
C4 = SubSP(C1,C2);
cout << "\nTong hai so phuc nay:"; DisplaySP(C3); cout << "\nHieu hai so phuc nay:"; DisplaySP(C4); return 0;
(37)SP SetSP(double real,double img) { SP tmp;
tmp.real = real; tmp.img = img; return tmp;
}
SP AddSP(SP C1,SP C2) { SP tmp;
tmp.real = C1.real + C2.real; tmp.img = C1.img + C2.img; return tmp;
}
SP SubSP(SP C1,SP C2) { SP tmp;
tmp.real = C1.real - C2.real; tmp.img = C1.img - C2.img; return tmp;
}
void DisplaySP(SP C) {
(38)C++
•
C++ cho phép định nghĩa lại chức
tốn tử có sẵn cách tiện lợi tự nhiên Điều gọi
đa hóa tốn tử.
•
Một hàm định nghĩa tốn tử có cú pháp sau:
data_type operator operator_symbol ( parameters )
{
………
}
Trong đó:
•
data_type
: Kiểu trả về.
•
operator_symbol
: Ký hiệu toán tử.
(39)#include <iostream.h>
typedef struct SP
{ double real; double img;} SP; SP SetSP(doublereal
, doubleimg
);void DisplaySP(SP C);
SP operator + (SP C1, SP C2); SP operator - (SP C1, SP C2);
int main() {
SP C1,C2,C3,C4;
C1 = SetSP(1.1,2.0); C2 = SetSP(-3.0,4.0);
cout << "\nSo phuc thu nhat:"; DisplaySP(C1); cout << "\nSo phuc thu hai:"; DisplaySP(C2); C3 = C1 + C2;
C4 = C1 - C2;
cout << "\nTong hai so phuc nay:"; DisplaySP(C3); cout << "\nHieu hai so phuc nay:"; DisplaySP(C4); return 0;
(40)SetSP(double real,double img) { SP tmp;
tmp.real = real; tmp.img = img; return tmp;
}
SP operator + (SP C1,SP C2) { SP tmp;
tmp.real = C1.real + C2.real; tmp.img = C1.img + C2.img;
return tmp; }
SP operator - (SP C1,SP C2) { SP tmp;
tmp.real = C1.real - C2.real; tmp.img = C1.img - C2.img;
return tmp; }
void DisplaySP(SP C) {
(41)Ví dụ sử dụng trỏ hàm
void swapValue(int &value1, int &value2){ int temp = value1;
value1 = value2; value2 = temp; }
int main(){
void(*pSwap) (int &, int &) = swapValue; int a = 1, b = 5;
cout << "Before: " << a << " " << b << endl; (*pSwap)(a, b);
cout << "After: " << a << " " << b << endl; return 0;
}
(42)Sắp xếp dãy số
bool ascending(int left, int right){ return left > right;
}
bool descending(int left, int right){ return left < right;
}
void selectionSort(int *arr, int length, bool (*comparisonFunc)(int, int)){
for (int i_start = 0; i_start < length; i_start++) { int minIndex = i_start;
for (int i_current = i_start + 1; i_current < length; i_current++){ if (comparisonFunc(arr[minIndex], arr[i_current])) {
minIndex = i_current; }
}
swap(arr[i_start], arr[minIndex]); // std::swap }
}
(43)Sắp xếp dãy số
int main() {
int arr[] = { 1, 4, 2, 3, 6, 5, 8, 9, };
int length = sizeof(arr) / sizeof(int);
cout << "Before sorted: ";
printArray(arr, length);
selectionSort(arr, length,
descending
);
cout << "After sorted: ";
printArray(arr, length);
return 0;
}
(44)Sắp xếp dãy số
int main() {
int arr[] = { 1, 4, 2, 3, 6, 5, 8, 9, };
int length = sizeof(arr) / sizeof(int);
cout << "Before sorted: ";
printArray(arr, length);
selectionSort(arr, length,
ascending
);
cout << "After sorted: ";
printArray(arr, length);
return 0;
}
(45)Khái quát hóa hàm (Function templates)
#include <iostream> using namespace std;
template <typename T> T maxval(T x, T y){
return (x > y) ? x : y; }
int main() {
int i = maxval(3, 7); // returns cout << i << endl;
double d = maxval(6.34, 18.523); // returns 18.523 cout << d << endl;
char ch = maxval('a', '6'); // returns 'a' cout << ch << endl;
return 0; }
(46)Hàm nặc danh - cú pháp lambda
#include <iostream> using namespace std;
void stdio_doing(int n) { n = n + 10;
cout << n << " "; }
void for_each (int *arr, int n, void (*func)(int a)){ for (int i = 0; i < n; i++) {
func(*(arr + i)); }
}
int main(){
int arr[] ={1, 2, 3, 4, 5} , n = 5; for_each(arr, n, stdio_doing);
return 0;
(47)Hàm nặc danh - cú pháp lambda
#include <iostream> using namespace std;
void for_each (int *arr, int n, void (*func)(int a)){ for (int i = 0; i < n; i++) {
func(*(arr + i)); }
}
int main(){
int arr[] ={1, 2, 3, 4, 5} , n = 5; for_each(arr, n, [] (int a){
a = a + 10;
cout << a << " "; });
return 0;
} 47
Lợi ích lambda không thiết phải khai báo tên hàm nơi khác, mà tạo hàm sử dụng chỗ (thường tác vụ nhỏ - dùng lần hay có chỗ gọi hàm đó)
(48)Hàm nặc danh - cú pháp lambda
(1) Mệnh đề bắt giữ (capture clause) (2) Danh sách tham số
(3) Tính bền vững lambda
(4) Ngoại lệ xảy lambda (5) Kiểu trả lambda
(6) Phần thân lambda
(49)Hàm nặc danh - cú pháp lambda
Mệnh đề bắt giữ (capture clause)
49
[ ] Không s d ng b t kỳ bi n bên thân hàmử ụ ấ ế
e.g [ ]( int i){ return i+j; } //error j bi n bên ngồi khơng đế ược captured
[& ] Đượ ục s d ng bi n bên qua tham chi u (ế ế by reference)
e.g [&]( int i){ j++; return i+j; } //changes made to j is reflected upon return
[=] Đượ ục s d ng bi n bên ngoài, nh ng d ng chép giá tr c a bi n (ế ị ủ ế by value)
e.g [=]( int i){ return i+j; } //j không thay đ i thân hàmổ
[&,j] B t kỳ bi n bên đấ ế ược captured qua tham chi u, ngo i tr bi n j đế ế ược captured qua giá tr ị
e.g [&,j]( int i){ j++; k++; return i+j+k; } //j tăng c c b k tăng giá tr cho c bên ụ ộ ị ả
ngoài hàm
[=,j] B t kỳ bi n bên đấ ế ược captured qua giá tr , ngo i tr bi n j đị ế ược captured qua tham chi u.ế
e.g [ ]( int i){ j++; k++; return i+j+k; }
[this] Cho phép s d ng this (OOP) nh b n saoử ụ ả
[&,&j] Error j ghi l i theo tham chi u theo m c đ nhạ ế ặ ị
[=,this] Error s d ng ụ =, this captured theo m c đặ ược
[i,i] Error i b l p l iị ặ
[&this] Error không th l y đ a ch c a ể ấ ị ỉ ủ this
(50)Ví dụ
#include <iostream> using namespace std;
int main(){ int m = 0; int n = 0;
auto func = [&, n] (int a) mutable { m = ++n + a;
};
func(4);
cout << m << endl << n << endl; }
Kết quả:
5
(51)Bài tập
•
Xây dựng cấu trúc thời gian Time chứa thông
tin giờ, phút đa hóa tốn tử
+
,
-
cho cấu
trúc thời gian này.
(52)Bài tập
•
Xây dựng hàm cấp phát động ma trận có kích
thước
n x m
.
(53)Bài tập
•
Xây dựng hàm cấp phát động ma trận có kích
thước
n x m
.
53
(54)Bài tập
•
Xây dựng hàm cấp phát động ma trận có kích
thước
n x m
.
54
(55)Bài tập
•
Xây dựng hàm cấp phát động ma trận có kích
thước
n x m
.
55
(56)Một vài ví dụ tối ưu mã C, C++
switch ( queue ) {
case : letter = 'W'; break;
case : letter = 'S'; break;
case : letter = 'U'; break;
}
Hoặc :
if ( queue == )
letter = 'W';
else if ( queue == )
letter = 'S';
else letter = 'U';
static char *classes="WSU"; letter = classes[queue];
(57)Một vài ví dụ tối ưu mã C, C++
(x >= && x < max)
có thể chuyển thành(unsigned)(x - min) < (max - min)
Giải thích:
int: -2
31… 2
31- 1
unsigned: … 2
32- 1
Nếu
x - >= 0
: Hai biểu thức tương đương
Nếu
x - <= 0
:
(unsigned) (x - min) = 2
32+ x – min
>= 2
31> max - min
(58)Một vài ví dụ tối ưu mã C, C++
int fact1_func (int n) {
int i, fact = 1;
for (i = 1; i
<=
n; i++) fact *= i;
return (fact);
}
int fact2_func(int n) {
int i, fact = 1;
for (i = n; i
!=
0; i ) fact *= i;
return (fact);
}
fact2_func nhanh hơn, phép thử != đơn giản <=
(59)Số thực dấu phẩy động
•
So sánh:
x = x / 3.0;
và
x = x * (1.0/3.0) ;
(biểu thức thực dịch)
•
Hãy dùng
float
thay
double
•
Tránh dùng
sin, exp
và
log
(chậm gấp 10 lần * )
•
Dùng
x * 0.5
thay
x / 2.0
•
x+x+x
thay
x*3
•
Mảng chiều nhanh mảng nhiều chiều
•
Tránh dùng đệ quy
(60)Ví dụ
Tính giai th a c a n
ừ
ủ
Đ nh nghĩa không đ quy n!
ị
ệ
n! = n * (n-1) * … * 1
Đ nh nghĩa đ quy:
ị
ệ
n! = 1
n u n=0
ế
n * (n-1)!
n u n>0
ế
Mã C++
int factorial(int n) {
if (n==0) return 1;
else
return (n * factorial(n -
1));
(61)Ví dụ
Tính
S(n) = 1/(1*2) + 1/(2*3) + + 1/( n*(n+1) )
S(n) = 1/2 n==1
= S(n-1)+1/(n*(n+1))
float S(int n) {
if ( n==1) return 0.5;
(62)Ví dụ
Tính t ng giá tr c a dãy s H(n), bi t
ổ
ị ủ
ố
ế
H(n) = n n<3
= 2*H(n-1)*H(n-2) n>2
long H(int n) {
if (n<3) return n;
else return 2*H(n-1)*H(n-2);
}
long Tong(int n) {
long tg=0;
for( int i=1; i<=n;i++)
tg+=H(i);
(63)Bài tập
Tính X(n) v i
ớ
•
X
o= 1
•
X
n= canba(n)*X
o+ canba(n-1)*X
1+ + canba(1)*X
n-1 (64)Ví dụ
X(n) = 1,2,3,5,11,41…… Y(n) = 1,1,2,6,30,330 …void main() { int n;
printf("\n Nhap n = "); scanf("%d",&n);
printf( "\n X = %d " ,X(n)); printf( "\n Y = %d " , Y(n)); getch();
}
long Y(int n); //prototype cua ham y long X(int n) {
if(n==0) return 1; else
return X(n-1) + Y(n-1); }
long Y(int n) { if(n==0)
return 1; else
(65)Bài tập 1
•
Xây d ng hàm đ quy in đ o
ự
ệ
ả
(66)Bài tập 2
•
Xây d ng hàm đ ki m tra xem
ự
ệ ể
(67)Bài tập 2
•
Phân tích
•
u c u
ầ
: ki m tra tính đ i x ng c a m t m ng
ể
ố ứ
ủ
ộ
ả
t ph n t t hai đ u c a m ng
ừ
ầ ừ
ầ
ủ
ả
•
Kích th
ướ
c đ quy
ệ
: s ph n t c a m ng
ố
ầ ủ
ả
•
Đi m d ng đ quy
ể
ừ
ệ
: phát hi n hai ph n t n m
ệ
ầ ằ
t i v trí đ i x ng khơng giá tr ho c
ạ
ị
ố ứ
ị
ặ
ki m tra h t ph n t đ u đ i x ng
ể
ế
ầ ề
ố ứ
•
Tr
ườ
ng h p t ng quát
ợ
ổ
: ph n t n m t i
ầ ằ
ạ
các v trí i j đ i x ng có giá tr ki m tra
ị
ố ứ
ị
ể
(68)Bài tập 3
•
Xây d ng hàm đ quy ki m tra
ự
ệ
ể
(69)Bài tập 4
•
M t palindrome m t t hay m t
ộ
ộ ừ
ộ
câu, đ c xuôi ng
ọ
ượ
c đ u gi ng nh
ề
ố
ư
nhau Vi t ch
ế
ươ
ng trình, v i gi i
ớ
ả
(70)Bài tập 5
•
Xây d ng hàm đ quy đ o ng
ự
ệ
ả
ượ
c
m t m ng s nguyên?
ộ
ả
ố
•
Xây d ng hàm đ o ng
ự
ả
ượ
c m t
ộ
(71)Bài tập
•
Vi t hàm đ quy tính giá tr ph n t r i tính t ng c a
ế
ệ
ị
ầ ồ
ổ
ủ
dãy s sau
ố
1,2,3,6,11,20,37,68,125
•
Vi t hàm đ quy tính giá tr ph n t r i tính t ng c a
ế
ệ
ị
ầ ồ
ổ
ủ
dãy s sau :
ố
1,2,3,7,13,23,43,79,145
(72)Bài tập
•
Vi t hàm đ quy tính ph n t c a dãy s sau v i n
ế
ệ
ầ ủ
ố
ớ
(73)•
Kh đ quy v i hàm tính giai th a
ử ệ
ớ
ừ
int FAC ( int n ) {
int k = 0;
int F = 1;
while ( k < n ) F = ++k * F;
return (F);
}
•
Kh đ quy v i hàm tính S(n)
ử ệ
ớ
int S ( int n ) {
int k = , tg = ;
while ( k < n ) {
k ++ ;
if (k%2 == 1) tg + = * k -1;
else tg -= * k + ;
}
(74)Ví dụ
Tìm ước chung lớn nhất
Gi i thu t đ quy
ả
ậ
ệ
int USCLN(int m, int n) {
if (n == 0) return m;
else USCLN(n, m % n);
}
• X là( m , n )
• P(X) USCLN(m ,n) • B(X) n ==
• D(X) l nh return mệ
• A(X) l nh r ngệ ỗ
• f(X ) f(m,n) = ( n , m mod n )
Kh đ quy
ử ệ
int USCLN(int m , int n ) {
while(n != ) { int sd = m % n ; m = n ;
n = sd ; }
(75)Ví dụ
Bài tốn Tháp Hà Nội
Đ quy
ệ
THN(n,X,Y,Z) ≡ if(n > 0) {
THN (n - 1, X, Z, Y); Move (X, Z );
THN (n - 1, Y, X, Z); }
Trong đó
• Bi n X b (n,X,Y,Z)ế ộ
• C(X) n<=0
• D(X), A(X) r ngỗ
• B(X) = B(n,X,Y,Z) move(X, Z)
• f(X) = f(n,X,Y,Z) = (n-1,X,Z,Y)
• g(X) = g(n,X,Y,Z) = (n-1,Y,X,Z)
Kh đ quy
ử ệ
THN {
Create_Stack (S) ;
Push (S ,(n,X,Y,Z,1)) ; Repeat
While (n > 0) begin
Push (S ,(n,X,Y,Z,2)) ; n = n - 1;
Swap (Y,Z) ; end ;
Pop (S,(n,X,Y,Z,k)) ; if ( k <> ) then begin Move (X ,Z ) ;
n = n - ; Swap (X,Y) ; end ;
(76)Ví dụ
Cho dãy s
1,2,3,7,14,27,55,110,219
ố
Vi t hàm đ quy tính s h ng th n c a dãy
ế
ệ
ố ạ
ứ
ủ
s (n > nh p t bàn phím), r i tính t ng
ố
ậ ừ
ồ
ổ
s h ng c a dãy
ố ạ
ủ
Sau đó, kh đ quy ch
ử ệ
ươ
ng trình trên
Cơng th c t ng quát
ứ ổ
S(n) = n, n <4
(77)Ví dụ
Ch
ươ
ng trình đ quy
ệ
int S(int n) { if (n<4)
return n; else
return S(n-1)+S(n-2)+S(n-3)*2; }
int main() {
int n,i,Tong=0;
printf("\n Vao n :"); scanf("%d",&n);
for(i=1;i<=n;i++) Tong+=S(i);
(78)Ví dụ
Kh đ quy
ử ệ
int main() {
int i,n,T=6; F1,F2,F3,F; printf("\n Vao n: "); scanf("%d",&n);
if (n==1) T=1;
else if (n==2) T=3; else if (n==3) T=6; else {
F1=1; F2=2; F3=3; for(i=4;i<=n;i++) {
F=2*F1+F2+F3; T+=F;
F1=F2; F2=F3; F3=F; }
(79)Ví dụ
Kh đ quy (dùng m ng)
ử ệ
ả
int main() {
int i,n,T=6, F[4]={1,2,3,7}; printf("\n Vao n : ");
scanf("%d",&n); if (n==0) T=1;
else if (n==1) T=3;
else if (n==2) T=6; else {
for(i=3;i<=n;i++) {
F[i%4] = F[(i-1)%4]+F[(i-2)%4]
+2 * F[(i-3)%4]; T+=F[i%4];
} }
printf("\n Tong = %d ",T); getch();
(80)Bài tập
•
Vi t hàm đ quy tính giá tr ph n t r i tính t ng c a
ế
ệ
ị
ầ ồ
ổ
ủ
dãy s sau, sau vi t ch
ố
ế
ươ
ng trình d
ướ ạ
i d ng khơng đ
ệ
quy:
T=1+2+3+6+11+20+37+68+125+
•
Vi t hàm đ quy tính giá tr ph n t r i tính t ng c a
ế
ệ
ị
ầ ồ
ổ
ủ
dãy s sau, sau vi t ch
ố
ế
ươ
ng trình d
ướ ạ
i d ng không đ
ệ
quy:
T=1+2+3+7+13+23+43+79+145+
(81)Bài tập
•
Vi t hàm đ quy tính ph n t c a dãy s sau v i n
ế
ệ
ầ ủ
ố
ớ
ph n t (n>4), r i tính t ng ph n t c a dãy s
ầ ử
ồ
ổ
ầ ủ
ố
1,2,3,4,4,5,8,11,12,14,21,30,35,40,56,…
1,2,3,4,6,9,14,21,32,48,73,110,167,252,
•
Sau vi t l i tồn b ch
ế ạ
ộ
ươ
ng trình tính t ng dãy s
ổ
ố
(82)Bài tập
•
Xây d ng hàm đ quy đ o ng
ự
ệ
ả
ượ
c
ph n t m t danh sách liên k t
ầ ử
ộ
ế
đ n?
ơ
•
Xây d ng hàm đ o ng
ự
ả
ượ
c ph n t
ầ ử
trong m t danh sách liên k t đ n không
ộ
ế ơ
(83)Hướng dẫn
•
Đ quy?
ệ
•
Đi m neo / d ng đ quy: NULL / ch có nút
ể
ừ
ệ
ỉ
•
Thao tác đ quy:
ệ
•
1 Chia danh sách thành hai ph n – node đ u tiên
ầ
ầ
ph n l i c a danh sách
ầ
ạ ủ
•
2 Th c hi n đ o ng
ự
ệ
ả
ượ
c đ quy cho ph n l i c a
ệ
ầ
ạ ủ
danh sách
•
3 K t n i ph n l i c a danh sách v i node đ u tiên
ế ố
ầ
ạ ủ
ớ
ầ
(84)Hướng dẫn
Gi i pháp sau có khơng?ả
Node* reverse(Node* head) {
if (head == NULL || head->next == NULL) return head;
Node* rest = reverse(head->next); head->next->next = head;
head->next = NULL; return rest;
(85)Hướng dẫn
•
Kh đ quy?
ử ệ
(86)Hướng dẫn
Gi i pháp sau có khơng?ả
void reverse() {
Node* current = head;
Node *prev = NULL, *next = NULL;
while (current != NULL) { next = current->next;
current->next = prev;
prev = current; current = next; }
(87)8
Bài tập: Kiểm tra chu trình danh
sách nối đơn
▪
Định nghĩa danh sách liên kết đơn gồm giá
trị nguyên, viết chương trình xác định danh sách
liên kết có chứa chu trình hay khơng.
▪
Phân tích
▫
Trong ví dụ có tồn chu trình:
8
2
5
3
7
1
6
4
5
3
7
1
6
4
5
…
(88)8
Bài tập: Kiểm tra chu trình danh
sách nối đơn
▪
Thuật toán: Floyd's Cycle-Finding Algorithm
▫
Đặt hai trỏ: trỏ di chuyển chậm
một trỏ di chuyển nhanh
▹
Con trỏ chậm
: khởi tạo trỏ vào phần tử đầu
danh sách (Head), lần lặp di chuyển
sang phần tử (1 bước)
▹
Con trỏ nhanh
: khởi tạo trỏ vào phần tử đầu
danh sách (Head), lần lặp di chuyển
sang phần tử phần tử
(2 bước)
▫
Nếu sau số lần lặp hữu hạn mà hai trỏ
cùng trỏ vào nút
danh sách tồn chu trình
(89)8
Bài tập: Kiểm tra chu trình danh
sách nối đơn
int kiemtrachutrinh(Node *head){
Node* slow = head, *fast = head; //khởi tạo trỏ while(slow && fast && fast->next){
slow = slow->next; //di chuyển trỏ chậm fast = fast->next->next;//di chuyển trỏ nhanh if(fast==slow){ //nếu có chu trình
return 1; }
}
(90)9
Bài tập 2
▪
Xây dựng chương trình khai báo danh
sách liên kết đơn chứa trị nguyên
▪
Thực hiện: tách danh sách thành
danh sách liên kết đơn con, danh sách
liên kết đơn chứa phần tử giá
trị nguyên tăng dần
(91)Bài tập
S d ng
ử ụ
danh sách móc n i kép v i nút đ u gi
ố
ớ
ầ
ả, xây d ng
ự
toán qu n lý m SV đ n gi n, v i ch c sau
ả
ể
ơ
ả
ớ
ứ
1.
Nh p d li u vào danh sách
ậ
ữ ệ
2.
Hi n th d li u l p theo th t tên
ể
ị ữ ệ
ớ
ứ ự
3.
Tìm ki m k t qu theo tên
ế
ế
ả
4.
S p x p theo m trung bình
ắ
ế
ể
V i thơng tin v m i sinh viên đ
ớ
ề ỗ
ượ
c đ nh nghĩa c u trúc sau
ị
ấ
typedef struct {int masv; // mã hiệu sv char malop[12];
(92)9
Bài tập 3
▪
Viết chương trình nhập vào mảng
các số nguyên, xác định xem liệu
có thể chia mảng thành hai mảng
con có tổng phần tử mảng
là nhau.
▫
Ví dụ: mảng {1, 5, 11, 5} chia
được (hai mảng {1, 5, 5}
{11})
▫
Ví dụ: mảng {1, 5, 3} không chia
(93)Bài tập
▪
S a ch
ử
ươ
ng trình đ tính tốn k t qu c a bi u
ể
ế
ả ủ
ể
th c h u t v i toán h ng t ng quát (có th s th c,
ứ
ậ ố ớ
ạ
ổ
ể
ố ự
có th âm…)
ể
▪
Xây d ng ch
ự
ươ
ng trình chuy n đ i bi u th c t trung
ể
ổ
ể
ứ ừ
t sang h u t , bi u th c trung t xâu ký t v i toán
ố
ậ ố
ể
ứ
ố
ự ớ
h ng t ng quát phép toán đ u tiên nh sau :
ạ
ổ
ộ ư
ư
(94)Bài tập 4
▪
Vi t m t ch
ế
ộ
ươ
ng trình:
▫
Nh p vào t bàn phím m t s nguyên d
ậ
ừ
ộ ố
ươ
ng có N ch s
ữ ố
▫
Nh p vào m t giá tr nguyên d
ậ
ộ
ị
ươ
ng M
▫
Hãy th c hi n xoá M ch s s N đ thu đ
ự
ệ
ữ ố
ố
ể
ượ
c
s cịn l i sau xố l n nh t có th , xây d ng thu t
ố
ạ
ớ
ấ
ể
ự
ậ
tốn s d ng Stack.
ử ụ
▫
Ví d : s 2019
ụ ố
▸Xoá ch s : 219ữ ố
▸Xoá ch s : 29ữ ố
(95)9
Xoá để số lớn nhất
▪ Input:
▫
Số nguyên dương có N chữ số
▫
M: số chữ số cần xoá (0<= M < N)
▪ Output:
▫
Số lớn sau xoá M chữ số
▪ Phân tích
▫
Chuyển đổi số thành xâu ký tự để thuận tiện xử
lý
▫
Nhận thấy xóa mà số lớn
lần xóa chữ phải tạo số lớn nhất
(96)9
Xoá để số lớn nhất
▪ Phân tích: sử dụng ngăn xếp
▸ Dãy ln dãy lớn tạo xóa
▸ Stack chứa chữ số chọn
▫
Ví dụ: số 3973811 gồm N=7 chữ số, cần xoá M=3
chữ số
▸ Duyệt chữ số từ trái sang phải, stack ban đầu rỗng
▸ Đọc chữ số đầu tiên: M=3 push vào stack
▹ Stack: (cần xoá M=3)
▸ Đọc chữ số tiếp theo: M=3 so sánh với chữ số đỉnh stack: > pop khỏi stack push vào thay thế, chữ số bị xoá
▹ Stack: (cần xoá M=2)
▸ Đọc chữ số tiếp theo: M=2 so sánh với chữ số đỉnh stack: < push vào stack
(97)9
Xoá để số lớn nhất
▪ Phân tích: sử dụng ngăn xếp
▫
Ví dụ: số 3973811 gồm N=7 chữ số, cần xoá M=3
chữ số
▸ Đọc chữ số tiếp theo: M=2 so sánh với chữ số đỉnh stack: < push vào stack
▹ Stack: (cần xoá M=2)
▸ Đọc chữ số tiếp theo: M=2 so sánh với chữ số
trong đỉnh stack: > pop khỏi stack (M=1), > pop khỏi stack (M=0) push vào thay thế, chữ số bị xoá
▹ Stack: (cần xoá M=0)
▸ Đọc chữ số tiếp theo: M=0 push vào stack
▹ Stack: (cần xoá M=0)
▸ Đọc chữ số tiếp theo: M=0 push vào stack
▹ Stack: 1 (cần xoá M=0)
(98)