Chương 4Mảng & các giải thuật với mảng Đặt vấn đề Trong rất nhiều bài toán chúng ta cần thao tác trên một dãy hoặc một bảng, .... gồm hữu hạn các phần tử cùng kiểu.. - một ma trận: có c
Trang 1Chương 4
Mảng & các giải thuật với mảng
Đặt vấn đề
Trong rất nhiều bài toán chúng ta cần thao tác trên một dãy (hoặc một bảng, ) gồm hữu hạn các phần tử cùng kiểu Chẳng hạn:
- một lớp học: có các phần tử là sinh viên.
- một ma trận: có các phần tử là số thực.
chính là mảng.
có cùng một kiểu dữ liệu.
Đặt vấn đề (tt)
Thông tin về sinh viên được lưu trữ trong một phần tử
dãy sinh viên
ma trận
Khai báo mảng
Ví dụ:
//mảng 1 chiều gồm 10 ptử a[0]->a[9]:
int a[10];
//mảng 2 chiều gồm 12 phần tử b[0][0]->b[2][3]: float b[3][4];
<kiểu phần tử> <tênbiếnmảng>[giớihạnchiều1] [giớihạnchiềuk]
Trang 2Lưu trữ mảng
Mảng được lưu trữ ở một vùng nhớ liên
tục trong RAM.
Hệ thống sẽ quản lý địa chỉ phần tử đầu
tiên (thứ 0) của mảng, từ đó có thể truy
xuất đến phần tử bất kỳ bằng cách tính
ra địa chỉ của phần tử đó.
Theo quy ước: tên mảng chính là địa chỉ
của phần tử đầu tiên của mảng.
a == &a[0]
Lưu trữ mảng (tt)
thể hiện logic
thể hiện vật lý trong RAM
Địa chỉ gốc của mảng
Truy xuất mảng
Quy tắc: truy xuất mảng thông qua từng phần
tử của nó.
Ví dụ 1: Giả sử có int a[10], b[3][4];
khi đó:
- để truy xuất đến phần tử thứ i của a ta dùng
cú pháp sau: a[i]
- tương tự: cú pháp b[i][j] để truy xuất đến phần
tử ở dòng i, cột j của ma trận b.
<tênbiếnmảng>[chỉ số1] [chỉ sốk]
Truy xuất mảng (tt)
Ví dụ 2: Hàm sau đây sẽ nhập dữ liệu cho mảng n số nguyên (giả sử a và n được khai báo toàn cục) void nhapDL()
{ int i;
for(i=0;i<n;++i) {
printf(“\nphan tu thu %d = “,i);
scanf(“%d”,&a[i]);
} }
Trang 3Mảng và con trỏ
Trong trường hợp mảng dùng làm tham số cho một hàm ta có 2
cách sử dụng sau:
Cách 1: Sử dụng khai báo hình thức.
Ví dụ 1:
void nhapDL(int a[], int n)
{
int i;
for(i=0;i<n;++i)
{
printf(“\nphan tu thu %d = “,i);
scanf(“%d”,&a[i]);
}
}
Khai báo hình thức (không cần chỉ rõ kích thước)
Mảng và con trỏ (tt)
Ví dụ 2: hàm in ma trận b, n dòng, m cột ra màn hình (giả sử b được khai báo số cột là 10).
void inMT(int b[][10], int n, int m) {
int i,j;
for(i=0;i<n;++i) {
for(j=0;j<m;++j)printf(“%5d”,a[i][j]);
printf(“\n”);//xuống dòng mới }
}
Đối với mảng 2 chiều, cần chỉ
rõ số cột khai báo (tại sao?)
Mảng và con trỏ (tt)
Khi đó các hàm trên có thể sử dụng như
sau:
int a1[100], a2[10][10], n, dong, cot;
nhapDL(a,n);
inMT(b,dong,cot);
Mảng và con trỏ (tt)
Cách 2: Sử dụng con trỏ làm tham số hình thức cho
mảng.
Ví dụ 1:
void nhapDL(int *p, int n) {
int i;
for(i=0;i<n;++i) {
printf(“\nphan tu thu %d = “,i);
scanf(“%d”, p+i );
} }
Trang 4Mảng và con trỏ (tt)
Giải thích:
int x[100], n;
lời gọi hàm nhập dữ liệu sẽ có dạng:
nhapDL(x,n);
Suy ra:
p=x=&x[0]
p+i = &x[i]
*(p+i) = x[i]
p[i] = x[i]
Mảng và con trỏ (tt)
void inMT(int *p, int n, int m) {
int i,j;
for(i=0;i<n;++i) {
for(j=0;j<m;++j)printf(“%5d”,*(p+10*i+j)); printf(“\n”);
} }
Mảng và con trỏ (tt)
2 0 1 4
4 5 10 3
lưu trữ logic của a2
giải thích:
Mảng và con trỏ (tt)
lưu trữ vật lý trong RAM của a2
2 0 1 4 4 5 10 3
Trang 5Các giải thuật trên mảng
Tính toán trên mảng:
Ví dụ 1: Tính tổng các phần tử dương
của mảng nguyên a, n phần tử.
int tongDuong(int *p, int n) {
int i,t=0;
for(i=0;i<n;++i)
if(p[i]>0)t+=p[i];
return t;
}
Các giải thuật trên mảng (tt)
i=2 t=2+a[2]=3 i=3 t=3+a[3]=7
i=5 t=7+a[5]=9
i=7 t=9+a[7]=10
2 0 1 4 -3 2 -8 1
0 1 2 3 4 5 6 7
Các giải thuật trên mảng (tt)
Tìm max-min:
Cho mảng a, n số nguyên Hãy tìm chỉ
số của phần tử lớn nhất.
int max(int *p, int n) {
int i,m=0;
for(i=1;i<n;++i)
if(p[m]<p[i])m=i;
return m;
}
Các giải thuật trên mảng (tt)
Giải thích:
2 0 1 4 -3 2 -8 1
0 1 2 3 4 5 6 7
i=0 i=1 i=2 i=3 i=4 i=5 i=6 i=7
m=0 m=0 m=0 m=3 m=3 m=3 m=3 m=3
Trang 6Các giải thuật trên mảng (tt)
Tìm kim:
Cho mảng a, n số nguyên Tìm vị trí xuất
hiện phần tử x.
int timKiem(int *p, int n, int x)
{
int i=0;
while(i<n&&p[i]!=x)++i;
if(i<n) return i;
else return -1; //quy ước.
}
Các giải thuật trên mảng (tt)
Giải thích:
2 0 1 4 -3 2 -8 1
0 1 2 3 4 5 6 7
i=0 i=1 i=2
x!=a[0]
x!=a[1]
x=a[2]
x=1
Các giải thuật trên mảng (tt)
Sắp xếp:
Cho dãy a, n số nguyên Yêu cầu sắp
xếp các phần tử của dãy theo thứ tự
tăng dần.
Ở đây trình bày 2 phương pháp sắp xếp:
- Phương pháp chọn (selection).
- Phương pháp hoán đổi trực tiếp
(interchange).
Phương pháp sắp xếp chọn
a[0] -> a[n-1] rồi hoán vị min với a[0].
a[1] -> a[n-1] rồi hoán vị min với a[1].
Bước i: Tìm phần tử min trong các phần tử a[i] -> a[n-1] rồi hoán vị min với a[i].
a[n-1] rồi hoán vị min với a[n-2].
Trang 7Phương pháp sắp xếp chọn (tt)
2 0 1 4 -3 2 -8 1
0 1 2 3 4 5 6 7
-8 0 1 4 -3 2 2 1
0 1 2 3 4 5 6 7
-8 0 1 4 -3 2 2 1
0 1 2 3 4 5 6 7
-8 -3 1 4 0 2 2 1
0 1 2 3 4 5 6 7
-8 -3 1 4 0 2 2 1
0 1 2 3 4 5 6 7
-8 -3 0 4 1 2 2 1
0 1 2 3 4 5 6 7
-8 -3 0 4 1 2 2 1
0 1 2 3 4 5 6 7
-8 -3 0 1 4 2 2 1
0 1 2 3 4 5 6 7
-8 -3 0 1 4 2 2 1
0 1 2 3 4 5 6 7
-8 -3 0 1 1 2 2 4
0 1 2 3 4 5 6 7
-8 -3 0 1 1 2 2 4
0 1 2 3 4 5 6 7
-8 -3 0 1 1 2 2 4
0 1 2 3 4 5 6 7
-8 -3 0 1 1 2 2 4
0 1 2 3 4 5 6 7
-8 -3 0 1 1 2 2 4
0 1 2 3 4 5 6 7
trước khi hoán vị sau khi hoán vị
Minh họa:
Phương pháp sắp xếp chọn (tt)
void selection(int a[], int n) {
int i,j,t,m;
for(i=0;i<n-1;++i) {
m=i;
for(j=i+1;j<n;++j)
if(a[m]>a[j])m=j;
if(m!=i) {
t=a[m];
a[m]=a[i];
a[i]=t;
} } }
Cài đặt
Phương pháp interchange
Tư tưởng: tượng tự phương pháp
selection Nhưng tại mỗi bước thay vì
hoán vị a[i] với phần tử min tìm được thì
a[i] sẽ được hoán vị lần lượt với các
phần tử nhỏ hơn nó để cuối cùng a[i]
chính là min.
Phương pháp interchange (tt)
2 0 1 4 -3 2 -8 1
0 1 2 3 4 5 6 7
-8 2 1 4 0 2 -3 1
0 1 2 3 4 5 6 7
-8 -3 2 4 1 2 0 1
0 1 2 3 4 5 6 7
-8 -3 0 4 2 2 1 1
0 1 2 3 4 5 6 7
-8 -3 0 1 4 2 2 1
0 1 2 3 4 5 6 7
-8 -3 0 1 1 4 2 2
0 1 2 3 4 5 6 7
-8 -3 0 1 1 2 4 2
0 1 2 3 4 5 6 7
-8 -3 0 1 1 2 2 4
0 1 2 3 4 5 6 7
trước khi hoán vị sau khi hoán vị a[i] với các
phần tử nhỏ hơn
-8 2 1 4 0 2 -3 1
0 1 2 3 4 5 6 7
-8 -3 2 4 1 2 0 1
0 1 2 3 4 5 6 7
-8 -3 0 4 2 2 1 1
0 1 2 3 4 5 6 7
-8 -3 0 1 4 2 2 1
0 1 2 3 4 5 6 7
-8 -3 0 1 1 4 2 2
0 1 2 3 4 5 6 7
-8 -3 0 1 1 2 4 2
0 1 2 3 4 5 6 7 Minh họa:
Trang 8Phương pháp interchange (tt)
void interchange(int a[], int n)
{
int i,j,t;
for(i=0;i<n-1;++i)
for(j=i+1;j<n;++j)
if(a[i]>a[j]) {
t=a[i];
a[j]=a[i];
a[i]=t;
} }
Cài đặt
Ví dụ về mảng 2 chiều
Ví dụ 1: Cho ma trận nguyên A, n dòng,
m cột Hãy viết các hàm:
- Tính tổng các phần tử dương của A.
- Đếm số phần tử trên đường chéo chính
là số nguyên tố.
- Tìm phần tử max của mảng.
Ví dụ về mảng 2 chiều (tt)
//hàm tính tổng các phần tử dương:
int tongDuong(int *p, int n, int m, int M)
{
int i,j,t=0;
for(i=0;i<n;++i)
for(j=0;j<m;++j)
if(*(p+M*i+j)>0)t+=*(p+M*i+j);
return t;
}
Ví dụ về mảng 2 chiều (tt)
//hàm đếm số phần tử là số nguyên tố trên //đường chéo chính:
int demNT(int *p, int n, int m, int M) {
int i,j,d=0;
if(n!=m)return -1;//không có đường chéo
for(i=0;i<n;++i) {
j=2;
while(*(p+M*i+i)%j)++j;
if(j==*(p+M*i+i))++d; //nếu là số nguyên tố thì đếm
} return d;
}
Trang 9Ví dụ về mảng 2 chiều (tt)
//hàm tìm phần tử max:
int timMax(int *p, int n, int m, int M)
{
int i,j,d,c;
d=c=0;
for(i=0;i<n;++i)
for(j=0;j<m;++j)
if(*(p+i*M+j)>*(p+d*M+c)) {
d=i;
c=j;
} return *(p+M*d+c);
}
Hỏi đáp