Tải bản đầy đủ (.pdf) (9 trang)

Kỹ thuật lập trình - Mảng và các giải thuật với mảng pot

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (110.96 KB, 9 trang )

Chươ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.

Khi đó cần có các cấu trúc dữ liệu phù hợp, đó
chính là mảng.

Mảng là dãy hữu hạn, có thứ tự các phần tử
có cùng một kiểu dữ liệu.

Mảng có thể có 1 hoặc nhiều chiều.
Đặt vấn đề (tt)
sv[0] sv[0]
sv[k]
Thông tin về sinh viên được lưu trữ trong một phần tử
dãy sinh viên
2 0 1 4
4 5 10 3
0 9 6 0
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]
Lư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)
2
0 1 4
4 5 10 3
thể hiện logic
0 9
6 02
0 1 4 4 5 10 3
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]);
}
}
Mả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);
}
}
Mả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)


Ví dụ 2: hàm in ma trận ra màn hình
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
p p+10
Cá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)
 Giải thích:
i=0 t=0+a[0]=2
i=1 t=2
i=2 t=2+a[2]=3
i=3 t=3+a[3]=7
i=4 t=7
i=5 t=7+a[5]=9
i=6 t=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
Các giải thuật trên mảng (tt)
 Tìm kim:
 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

Bước 0: Tìm phần tử min trong các phần tử
a[0] -> a[n-1] rồi hoán vị min với a[0].

Bước 1: Tìm phần tử min trong các phần tử
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].




Bước n-2: Tìm phần tử min giữa a[n-2] và a[n-
1] rồi hoán vị min với a[n-2].
Phươ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:
Phươ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;
}
Ví 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

×