You are on page 1of 54

Ôn Tập

Function, Array, Struct


Nội dung
▪ Hàm
▪ Mảng
o 1D-Array
o 2D-Array
▪ Kiểu struct
▪ Tạo số ngẫu nhiên trong C/C++
▪ Giới thiệu Ma trận thưa (sparse matrix) vs. dense matrix (option)
Macro vs. Function
▪ Macro: được dùng để chỉ những định nghĩa được viết ở phần Preprocessor, thay vì
đặt nó vào trong phần thực thi của file nguồn
Ví dụ : #define TONG_HAI_SO(x, y) (x) +(y)
▪ Function: là một loại chương trình con, gồm tên hàm, các tham số và thân hàm
(chứa các phát biểu chương trình), thực thi một việc cụ thể.
Ví dụ: int TongHaiSo(int x, int y)
{
return x+y;
}
Macro vs. Function
Ví dụ: tìm số lớn nhất giữa 2 số a và b

Macro Function
#include <stdio.h> #include <stdio.h>
#define MAX(A, B) ((A) > (B) ? (A) : (B)) int timMax(int, int); // prototype
int main() int main()
{ {
int a = 5, b = 7; int a = 5, b = 7;
float c = 5.6, d = 4.5; printf("\nMAX= %d", timMax (a, b));
printf("\nMAX= %d", ((a) > (b) ? (a) : (b))); return 0 ;
return 0 ; }
} int timMax(int x, int y) Gọi hàm
{
return ((x) > (y) ? (x) : (y));
}

Định nghĩa hàm


Ví dụ
#include <iostream> void power_2(int ix, int in)
using namespace std; {
Tính x^n // khai bao prototype int i, ip = 1;
int power(int, int); for(i = 1; i <= in; i++)
void power_2(int, int); ip *= ix;
// ham tinh so mu cout<<"ket qua:" <<ip<<endl;
int power(int ix, int in) }
{ int main()
int i, ip = 1; {
for(i = 1; i <= in; i++) int kq = power(2, 3);
ip *= ix; cout<<"2^3 =" <<kq<<endl;
return ip;
} power_2(2,3);
return 0;
}
Ví Dụ Tăng giá trị của biến lên một đơn vị
Tham chiếu và tham trị các thay đổi cho tham số hình thức
(trong hàm) không làm thay đổi đối với tham số
thực.
#include <stdio.h>
void thamtri(int ix, int iy) int main()
{ {
int ia = 5, ib = 5;
ix += 1; //cong ix them 1
thamtri(ia, ib);
iy += 1; //cong iy them 1 // ia = 5 ; ib = 5
} printf("a = %d, b = %d\n", ia, ib);

void thamchieu(int &ix, int &iy) thamchieu(ia, ib);


{ // ia =6; ib= 6
ix += 1; //cong ix them 1 printf("a = %d, b = %d\n", ia, ib);
iy += 1; //cong iy them 1 return 0;
}
}
toán tử địa chỉ &
tham số hình thức và tham số thực cùng địa chỉ
mọi thay đổi đối với tham số hình thức cũng làm thay đổi tham số thực.
Ví dụ: #include <iostream>
using namespace std;
Biến toàn cục (global variable) void local_func();
và biến cục bộ (local variable) int global_var = 10; // Biến toàn cục
int main()
{
cout<<"global var = " << global_var <<endl; // 10
local_func();
// ra khoi ham local_func()
cout<<"global var = " << global_var<<endl; // 20
return 0;
}
void local_func()
{
cout<<"global var in locAl function = " << global_var <<endl; // 10
int global_var = 5; // biến cục bộ
cout<<"local var = " <<global_var <<endl; //5
::global_var = 20;
cout<<"local var = " <<global_var <<endl; //5
cout<<"global var in locAl function = " << ::global_var <<endl; //20
}
Array: 1D-Array
▪ Chỉ số của mảng bắt đầu từ 0 -> N-1 ( với N là số lượng phần tử của mảng)
▪ Toán tử [] : toán tử lấy chỉ số (chỉ dùng cho các dãy vùng nhớ liên tiếp)
<Kiểu_Cơ_Sở> <Tên_Biến_Mảng>[<Số_Phần_Tử>];

Ví dụ: Mảng a có 5 phần tử


int a[10]; // (khai báo 10 ô nhớ, nhưng số lượng phần tử của mảng là 5)
a[0] = 1;
a[1] = 10;
a[2] = 21;
a[3] = -1;
a[4] = -4;
Lưu ý:
▪ Không thể dùng biến mảng như thông thường.
int a[6];
a = -2; // ERROR
cout<<a; // in ra gì???

▪ Mà phải dùng từng phần tử trong chúng. Mỗi phần tử được dùng như một biến
đơn.
int a[6];
a[1] = -2;
cin>>a[0]; // nhập vào a[0]
cout<<a[0]*a[1];
Biến mảng là tham số của hàm
▪ Tham số được khai báo như khai báo biến mảng.
Ví dụ: void SapXepTang(int a[100]);
Tham số kiểu mảng truyền cho hàm chính là địa chỉ của phần tử đầu tiên của mảng
Có thể không cần xác định số phần tử của mảng
Mảng được chuyển tham chiếu (Mảng có thể thay đổi nội dung sau khi thực hiện hàm)
Ví dụ: Hàm xuất nội dung một mảng các số nguyên:
void xuatMang(int a[], int N);
Ví dụ: Hàm nhập nội dung một mảng các số nguyên:
void nhapMang(int a[], int &N); // lưu ý khi nhập N trong hàm
Biến mảng là tham số của hàm
Lưu ý: Số lượng phần tử thực sự truyền qua biến khác
void SapXepTang(int a[100], int N);
void SapXepTang(int a[], int N);

int tinhtongMang(int A[], int N);


Lời gọi hàm void sapxepTang(int A[], int N);
void xoaDau(int A[], int &N);
int main()
{
int a[100], n;
tinhtongMang(a,n);
sapxepTang(a,n);
xoaDau(a,n);
}
Ví dụ:
void NhapMang(int a[], int &n) #include <iostream>
{ using namespace std;
cout<<"Nhap so luong phan tu n:"; void NhapMang(int a[], int &n); // prototype
cin>>n; void XuatMang(int a[], int n); // prototype
int main()
for (int i = 0; i < n; i++) {
{ int A[100]; // khai báo biến mảng
cout<<"Nhap phan tu thu "<< i <<" :"; int N; // số lượng phần tử trong mảng
cin>>a[i]; NhapMang(A,N);
// có thể dùng scanf để nhập XuatMang(A,N);
// scanf("%d", &a[i]); return 0;
} }
}

void XuatMang(int a[], int n)


{
cout<<"Cac phan tu cua mang:";

for (int i = 0; i < n; i++)


cout<<a[i]<<"\t";

cout<<endl;
}
Hàm Tìm Kiếm
#include <iostream>
int TimKiem(int a[], int n, int x) using namespace std;
{ void NhapMang(int a[], int &n);
for (int i= 0; i < n; i++) void XuatMang(int a[], int n);
if (a[i] == x) int TimKiem(int a[], int n, int x);
return i; int main()
{
int A[100], N, x, k;
return -1;
NhapMang(A,N);
} XuatMang(A,N);
cout<<"tim phan tu x:";
cin>>x;
k = TimKiem(A,N,x);
if (k!=-1)
cout<<"\n x tai vi tri:"<<k;
else
cout<<"\n khong tim thay";
return 0;
}
Ví dụ:
Tính tổng
int Tong(int a[], int n)
{
int tong = 0;
for (int i= 0; i < n; i++)
if (a[i] thỏa yêu cầu bài toán) // tùy yêu cầu điều kiện khác nhau
tong = tong + a[i];

return tong;
}
Ví dụ
Đếm số lượng phần tử thỏa điều kiện

int Demsoluong(int a[], int n)


{
int dem = 0;
for (int i= 0; i < n; i++)
if (a[i] thỏa yêu cầu bài toán) // tùy yêu cầu điều kiện khác nhau
dem++;

return dem;
}
Ví dụ: Kỹ thuật đặt cờ hiệu
Kiểm tra mảng a có phải là mảng toàn các số nguyên tố hay không?

int LaSNT(int n) int KiemTra(int a[], int n)


{ {
int flag = 1; // thảo đk
int i, dem = 0;
for (int i = 0; i < n ; i++)
for (i = 1; i <= n; i++) {
if (n%i == 0) if (LaSNT(a[i]) == 0) //không là SNT
dem++; {
flag = 0;
if (dem == 2) break;
return 1; }
return 0; }
} if (flag == 1)
return 1;
else
return 0;
}
Ví dụ: Kỹ thuật đặt lính canh
int TimMax(int a[], int n)
{
int max = a[0]; // max là lính canh

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


if (a[i] > max)
max = a[i];

return max;
}
Ví dụ : Kỹ thuật cầm canh (Sentinel)
Giả sử có đủ vùng nhớ để gán a[n] = x; trước vòng lặp while
Tìm kiếm phần tử x trong mảng - > chuyện gì xảy ra?????

int TimKiem(int a[], int n, int x)


{
int i = 0; a[n] = x;
while ((i<n) && (a[i]!=x)) 1 4 5 7 9 0 X=20
i++;
if(i==n) x = 20
return -1; //không tìm thấy
return i; //tìm được tại vị trí i
}
Sắp xếp trên mảng
void SapXepTang(int a[], int n)
{
int i, j;

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


{
for (j = i + 1; j < n; j++)
{
if (a[i] > a[j])
HoanVi(a[i], a[j]);
}
}
}

void HoanVi(int &x, int &y)


{
int tam = x; x = y; y = tam;
}
Ví dụ:
Sắp xếp các phần tử trên mảng sao cho các số dương tăng dần và các số âm giảm dần
2D - Array
Cú pháp dùng cho mảng hai chiều (2D-Array):
<Kiểu_Cơ_Sở> <Tên_Biến_Mảng>[<N1>] [<N2>];
N1, N2: số lượng phần tử mỗi chiều
Ví dụ: int A[3][4]; // mảng 2 chiều A có 3 dòng và 4 cột

0 1 2 3
A
Ví dụ:
0 int a[10][20], b[10][20];
1 float c[5][10];
char d[10][20];
2
Truy xuất đến một phần tử
Thông qua chỉ số: truy xuất thông tên mảng và chỉ số tại dòng và cột tương ứng
<tên biến mảng>[<chỉ số dòng>][<chỉ số cột>];
B[0][3]
int B[3][5];
1 6 -2 3
0 37 43 51
B[1][0] 1 93 34 0

Truy xuất phần tử tại dòng i, cột j: B[i][j] B[2][3]


Các truy xuất
Hợp lệ: B[0][0], B[0][1], …, B[2][2], B[2][3]
Không hợp lệ: B[-1][0], B[4][4], B[3][7]
Truyền mảng cho hàm
❖ Truyền mảng cho hàm
Số lượng phần tử thực sự truyền qua biến khác

void XuatMangHaiChieu(int a[50][100], int m, int n);


void XuatMangHaiChieu (int a[][100], int m, int n); m là số dòng, n là số cột

Lời gọi hàm


void NhapMangHaiChieu(int a[][100], int &m, int &n);
void XuatMangHaiChieu(int a[][100], int m, int n);
void main()
{
int a[50][100], m, n;
NhapMangHaiChieu (a, m, n);
XuatMangHaiChieu (a, m, n);
}
Hàm nhập mảng và xuất mảng
void NhapMangHaiChieu(int a[][MAXC], int &m, int &n)
{
cout<<"Nhap so dong, so cot cua mang:";
cin>>m>>n; #include <iostream>
#define MAXD 50
int i, j; #define MAXC 100
for (i=0; i<m; i++) void NhapMangHaiChieu(int a[][MAXC], int &m, int &n);
for (j=0; j<n; j++) void XuatMangHaiChieu(int a[][MAXC], int m, int n);
{ int main()
{
cout<<"Nhap phan tu:";
int a[MAXD][MAXC];
cin>>a[i][j]; int n,m;
} NhapMangHaiChieu(a,m,n);
} XuatMangHaiChieu(a,m,n);
return 0;
void XuatMangHaiChieu(int a[][MAXC], int m, int n) }
{ // hàm nhập mảng
int i, j; // hàm xuất mảng
for (i=0; i<m; i++)
{
for (j=0; j<n; j++)
cout<<a[i][j];

cout<<endl;
}
}
Hàm nhập mảng và xuất mảng
void xuatmang(int a[][MAX], int m , int n)
{ int i , j;
for(i =0; i<m;i++)
{
for(j=0; j<n; j++) Goi ham trong ham main
{ int main()
cout<<a[i][j] << “ ”;
{
int a[MAX][MAX];
}
int n,m;
cout << endl; // in xuống dòng nhapmang(a,m,n);
} xuatmang(a,m,n);
} return 0;
}
Tính tổng một cột
int TongCot(int a[][100], int m, int c)
{
int i, tong;

tong = 0;

for (i=0; i<m; i++) // Duyệt các dòng


tong = tong + a[i][c];

return tong;
}
Tìm kiếm
int TimKiem(int a[][100], int m, int n, int x)
{
int i, j;
for (i=0; i<m; i++)
for (j=0; j<n; j++)
if (a[i][j] == x)
{
cout<<"tai dong:"<<i;
cout<<"tai cot:"<<j;
return 1;
}
return 0;
}
Structure
▪ Struct (Cấu trúc) : là kiểu dữ liệu gồm một nhóm các thành phần có kiểu không
giống nhau, mỗi thành phần được xác định bằng một tên riêng biệt.

typedef struct <TênKiểu>


{
<Kiểu dữ liệu thành phần> <Tên thành phần>;
<Kiểu dữ liệu thành phần> <Tên thành phần>;
<Kiểu dữ liệu thành phần> <Tên thành phần>;
<Kiểu dữ liệu thành phần> <Tên thành phần>;
….
};
Cách khai báo biến có kiểu structure
Khai báo biến kiểu cấu trúc
▪ Cú pháp: struct <tên kiểu cấu trúc> <tên biến cấu trúc>;
(trong C++ có thể bỏ struct)
▪ Nếu dùng typedef: <tên kiểu cấu trúc> <tên biến cấu trúc>;
Ví dụ: Khai báo biến đơn kiểu cấu trúc

typedef struct Point2D typedef struct PhanSo


{ {
float x; int tuso;
float y; int mauso;
}; };
// khai báo biến P1,P2
Point2D P1,P2; PhanSo Ps1,Ps2;
Khai báo biến kiểu cấu trúc
▪ Khai báo mảng cấu trúc: cũng tương tự khai báo biến mảng trên các kiểu dữ liệu
khác .
Cú pháp: <tên kiểu cấu trúc> <tên biến mảng cấu trúc>[HẰNG_SỐ];

typedef struct Point2D typedef struct PhanSo


{ {
float x; int tuso;
float y; int mauso;
}; };
// khai báo biến P1,P2
Point2D P1,P2; PhanSo Ps1,Ps2;
// mảng cấu trúc //mảng phân số
Point2D ArrayP[100]; PhanSo Ps[50];
Truy xuất các thành phần trong struct
❖ Đặc điểm
▪ Không thể truy xuất trực tiếp
▪ Truy xuất thông qua toán tử thành phần cấu trúc . hay còn gọi là toán tử chấm (dot operation) và tên
thành phần
Cú pháp: <tên biến cấu trúc>.<tên thành phần>
Ví dụ:

typedef struct Point2D


{
float x;
float y;
};
Point2D P1={1.5,0.5},P2={2,4};
cout << P1.x << " "<< P1.y << endl;
cout << P2.x << " "<< P2.y << endl;
/* Danh sach nhan vien */
Ví dụ: Nhập xuất danh
#include <iostream>
sách nhân viên #include <stdlib.h>
using namespace std;
typedef struct TDate
{
int ngay;
int thang;
int nam;
Lưu ý: };
typedef struct nhanvien
Thành phần của cấu trúc là cấu trúc khác {
Thành phần cấu trúc là biến mảng
int manv;
char hoten[30];
TDate dob;
};
int main()
{ nhanvien snv[50];
int i, n; Ví dụ: Nhập xuất danh
cout<<"Nhap vao luong so nhan vien:"; sách nhân viên
cin>>n;
//Nhap danh sach nhan vien
for(i = 0; i <n; i++)
{
cout<<"Nhap vao ma nhan vien thu "<< i + 1 << ":";
cin>>snv[i].manv;
cout<<"nhap vao ngay sinh:";
cin>>snv[i].dob.ngay>>snv[i].dob.thang>>snv[i].dob.nam;
cout<<"Nhap vao ho ten: ";
fflush(stdin); // ko co dong nay ????
gets(snv[i].hoten); // gets dugn nhap chuoi ky tu
}
//in danh sach nhan vien …
for(i = 0; i<n; i++)
{
cout<<snv[i].manv <<endl;
cout<<snv[i].dob.ngay <<"/" << snv[i].dob.thang <<"/"<<snv[i].dob.nam <<endl;
cout<<snv[i].hoten <<endl << endl;
}
return 0;
}
Các lưu ý về cấu trúc
❖ Truyền cấu trúc cho hàm
▪ Giống như truyền kiểu dữ liệu cơ sở
Tham trị (không thay đổi sau khi kết thúc hàm)
Tham chiếu (thay đổi sau khi kết thúc hàm)
▪ Ví dụ

typedef struct DIEM


{
int x, y;
};
void xuat1(int x, int y) { … };
void xuat2(DIEM diem) { … };
void xuat3(DIEM &diem) { … };
Bài Tập
Ôn tập lại các bài tập ve function, array và struct trong môn học cơ sơ lập trình
Tạo ngẫu nhiên trong C/C++
▪ Hàm srand()
Cú pháp: void srand (unsigned int seed);
Dùng để khởi tạo một số ngẫu nhiên theo một số seed.

Để cho mỗi số seed khác nhau người ta thường dùng kèm với unsigned int
time(NULL) trong thư viện time.h, hàm time(NULL) trả về số giây đã trôi qua kể từ
ngày 1/1/1970.

▪ Hàm srand() thường được gọi trước khi gọi hàm rand()
Tạo ngẫu nhiên trong C/C++
▪ Hàm rand()
Cú pháp: int rand(void);
Trả về một số nguyên giả random trong khoảng từ 0 đến RAND_MAX.
Hằng RAND_MAX được định nghĩa trong stdlib.h đảm bảo ít nhất bằng 32767.

Nếu chỉ dùng hàm rand() thì sẽ cho ra những số random giống nhau mỗi lần chạy, vì
vậy người ta thường khai báo srand(time(NULL)) trước để kết quả random mỗi lần
mỗi khác nhau.

Để lấy số ngẫu nhiên từ 0 đến n, ta sử dụng rand()%(n+1)


Để lấy số ngẫu nhiên từ a đến b, ta sử dụng a + rand()%(b-a+1)
Tạo ngẫu nhiên trong C/C++
#include <iostream>
#include<time.h>
using namespace std;
int main()
{
int a, b;
srand(time(NULL));
cout<<rand()%100<<endl; //Ngẫu nhiên từ 0 đến 99
cout<<50+rand()%51; // 50 đến 100
return 0;
}
Câu hỏi
Phát sinh ngẫu nhiên mảng các số nguyên có K phần từ (3 K  10). Yêu cầu các
phần tử được phát sinh ngẫu nhiên trong đoạn [1,10000]

Để lấy số ngẫu nhiên từ 0 đến n, ta sử dụng rand()%(n+1)


Để lấy số ngẫu nhiên từ a đến b, ta sử dụng a + rand()%(b-a+1)
Tạo ngẫu nhiên trong C/C++
▪ Tạo ngẫu nhiên Số thực:
Để lấy giá trị từ 0.0 to 1.0

float r = static_cast (rand()) / static_cast (RAND_MAX);


Tạo ngẫu nhiên trong C/C++
C code:
#include <stdio.h> /* printf, NULL */
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */

int main()
{
srand (time(NULL)); // seed initialization
for (int i = 0; i < 10; ++i)
{
float r = (float) (rand()) / (float) (RAND_MAX);
printf("%f\n", r);
}

return 0;
}
Tạo ngẫu nhiên trong C/C++
C++ code
#include <iostream> /* std::cout, std::enld */
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */

int main()
{
srand (time(NULL)); // seed initialization
for (int i = 0; i < 10; ++i)
{
float r = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
std::cout << r << std::endl;
}

return 0;
}
Sparse matrix vs. Dense matrix
▪ Ma trận thưa (Sparse matrix) là loại ma trận có kích thước lớn nhưng phần lớn các
phần tử là 0.
▪ Thực hiện tính tóa trên ma trận thưa, ta thường quan tâm đến không gian lưu trữ
và tốc độ tính toán sao cho tối ưu nhất.
Sparse matrix - applications
Ví dụ: The NYC subway system
Biễu diễn bằng ma trận kề
Mỗi trạm có liên kết với nhau sẽ được biễu diễn bởi một trọng số (khác 0 )
trong ma trận.

Ví dụ

Or the graph of the web


Sparse matrix - applications
Ví dụ: Computer vision – bài toán background subtraction
Sparse matrix - applications
Ví dụ: Computer vision – bài toán background subtraction (2)
Sparse matrix - applications
Ví dụ: Audio signal processing – bài toán lyric and music separation
Sparse matrix - applications
Ví dụ: Face analysis system – bài toán illumination normalization
Sparse matrix
▪ Lưu trữ ma trận thưa (có nhiều cách): chỉ lưu trữ thông tin của các phần tử khác 0
Dùng Arrays
Dùng Linked Lists
DOK (Dictionary of keys)
LIL (List of lists)
COO (Coordinate list)
CSR (Compressed Sparse Row)
CSC (Compressed Sparse Column)

Sparse matrix
▪ Dùng Arrays
Lưu trữ thông tin các phần từ khác không dùng
triples- (Row, Column, value)
Mảng hai chiều với 3 dòng
Row : chỉ số của dòng
Column: chỉ số của cột
Value : giá trị tương ứng
Sparse matrix

Dùng Linked Lists

* Học trong môn Cấu trúc


dữ liệu và giải thuật
Bài tập
Nhập ngẫu nhiên hai ma trận thưa kích thước NxN.
A) Biễu diễn ma trận thưa bằng triples- (Row, Column, value)
B) Tính tổng hai ma trận
C) Tìm ma trận chuyển vị
* Tìm hiểu thuật toán nhân nhanh hai ma trận thưa. (option)

You might also like