▹ 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ả ha[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 vuông 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 phần tử mảng
(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ấ3p phát vùng nhớ cho ma trận A
if(!AllocMatrix(&A,M,N)) {
cout << "Khong du bo nho! "
<< endl; return 1;
}
//Cấ3p phát vùng nhớ cho ma trận B
if(!AllocMatrix(&B,M,N)) {
(25)//Cấ3p 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); return 0;
(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ấ3p 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; }
• Để hoá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; }
• Để hố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 hố tố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ề.
(39)#include <iostream.h>
typedef struct SP { double real; double img;} SP;
SP SetSP(double real, double img); 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: -231 … 231 - 1
unsigned: … 232 - 1
Nếu x - >= 0: Hai biểu thức tương đương Nếu x - <= 0:
(unsigned) (x - min) = 232 + x – min
>= 231 > 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 -
(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 ớ
•Xo = 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
(66)Bài tập 2
•Xây d ng hàm đ ự ệ ki m tra xem ể m t m ng s nguyên có đ i ộ ả ố ố
(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 ể m t m ng có giá tr ph n t ộ ả ị ầ ử
theo th t tăng d n (ho c gi m ứ ự ầ ặ ả
(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 ớ ả
thu t đ quy, đ c m t dòng t bàn ậ ệ ọ ộ ừ
phím vào báo cho bi t có ph 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 ộ
m ng s nguyên không dùng đ ả ố ệ
(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 : ố
(72)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ầ ử ồ ổ ầ ủ ố
(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:
(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 cá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 m t danh sách liên k t đ n ử ộ ế ơ
(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? ử ệ
dùng vòng
(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:
825371645371645 …
(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; }
}
return 0; //nếu khơng có chu trình
(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})
(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 ố ậ ố ể ứ ố ự ớ
(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 l i sau xố l n nh t có th , xây d ng thu t ố ạ ớ ấ ể ự ậ
toán s d ng Stackử ụ .
▫Ví d : s 2019ụ ố ▸Xố 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ố
trong đỉ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ố
(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ố
trong đỉ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)▪ Thứ tự trước: 15, 6, 3, 2, 4, 7, 13, 9, 18, 17, 20
▪ Thứ tự giữa: 2, 3, 4, 6, 7, 9, 13, 15, 17, 18, 20
▪ Thứ tự sau: 2, 4, 3, 9, 13, 7, 6, 17, 20, 18, 15