You are on page 1of 52

Chương 2

Mảng
(Buổi 2)
Giới thiệu
Chương này trình bày một loại danh sách
tuyến tính thường dùng, đó là mảng.
Nội dung của chương gồm:
™ Định nghĩa mảng
™ Khai báo và khởi tạo mảng
™ Sử dụng các phần tử của mảng
Định nghĩa mảng
™ Mảng (array) là một tập hợp có chỉ mục bao
gồm các phần tử có cùng kiểu.
™ Một mảng có các phương thức (method) và
các thuộc tính (attribute).
array
0
1


n

Hình 2.1. Biểu diễn một mảng.


Khai báo và khởi tạo mảng
™ Một mảng được khai báo theo cú pháp sau:
type[] array_name;
trong đó:
type là tên kiểu dữ liệu của các phần tử của mảng.
array_name là tên mảng.
ƒ Ví dụ: Khai báo mảng names mà mỗi phần tử chứa
một chuỗi.
string[] names;
Khai báo và khởi tạo mảng
™ Một mảng là một đối tượng thuộc kiểu
System.Array.
™ Sau khi khai báo một mảng, ta phải khởi tạo
mảng này để xác định kích thước của mảng (số
phần tử của mảng).
ƒ Ví dụ: Khởi tạo mảng names có 10 phần tử.
names = new string[10];
Khai báo và khởi tạo mảng
™ Có thể khai báo và khởi tạo một mảng trong
cùng một phát biểu.
ƒ Ví dụ: Khai báo và khởi tạo mảng names có 10
phần tử thuộc kiểu chuỗi.
string[] names = new string[10];
™ Khi khởi tạo một mảng, giá trị ban đầu của các
phần tử là:
f giá trị mặc định của kiểu của mảng (đối với kiểu
giá trị)
f null (đối với kiểu tham chiếu)
Khai báo và khởi tạo mảng
ƒ Ví dụ:
int[] numbers = new int[5];
mảng numbers có 5 phần tử, mỗi phần tử chứa số 0
(giá trị mặc định của kiểu int).
Khai báo và khởi tạo mảng

Kiểu Giá trị mặc định


numeric (int, long, …) 0
bool false
char '\0' (null)
enum 0
reference null

Bảng 2.1. Giá trị mặc định của các kiểu


Khai báo và khởi tạo mảng
™ Có thể khai báo, khởi tạo một mảng và gán giá
trị ban đầu cho các phần tử trong cùng một
phát biểu.
ƒ Ví dụ: Khai báo và khởi tạo mảng numbers có 5
phần tử thuộc kiểu nguyên, lần lượt chứa các số
1, 5, 10, 15, 20.
int[] numbers = new int[] {1,5,10,15,20};
hoặc
int[] numbers = {1,5,10,15,20};
trong đó {1,5,10,15,20} được gọi là danh sách
khởi tạo (initialization list).
Khai báo và khởi tạo mảng

Ghi chú:
™ Khi dùng danh sách khởi tạo, ta không cần phải
chỉ định số phần tử của mảng.
™ Số phần tử của mảng là số phần tử của danh sách
khởi tạo.
Khai báo và khởi tạo mảng
int[] numbers = new int[] {1,5,10,15,20};

kiểu int numbers


chỉ mục 1
0
của phần tử
1 5
2 10
3 15
4 20

Hình 2.2. Mảng numbers có 5 phần tử, chứa các số 1, 5, 10, 15, 20.
Sử dụng các phần tử của mảng
™ Gán giá trị cho một phần tử của một mảng theo
cú pháp sau:
array_name[index] = value;
trong đó:
array_name là tên mảng.
index là chỉ mục của phần tử của mảng.
value là giá trị được gán cho phần tử của mảng.
ƒ Ví dụ: Gán chuỗi “SPKT” cho phần tử 2 của mảng
names.
names[2] = "SPKT";
Sử dụng các phần tử của mảng
™ Truy xuất một phần tử của một mảng theo cú
pháp sau:
array_name[index]
trong đó:
array_name là tên mảng.
index là chỉ mục của phần tử của mảng.
ƒ Ví dụ: Gán giá trị của phần tử 2 của mảng names
cho biến myName.
myName = names[2];
Sử dụng các phần tử của mảng
™ Truy xuất tất cả phần tử của một mảng:
f Dùng vòng lặp for với cận trên là:
y số phần tử của mảng
y thuộc tính Length
y phương thức GetUpperBound( )
f Dùng vòng lặp foreach
Sử dụng các phần tử của mảng
// Truy xuat mang: can tren la so phan tu cua mang
int sum = 0;
for (int i = 0; i < 5; i++)
sum = sum + numbers[i];

// Truy xuat mang: can tren la Length


int sum = 0;
for (int i = 0; i < numbers.Length; i++)
sum = sum + numbers[i];

// Truy xuat mang: can tren la GetUpperBound( )


int sum = 0;
for (int i = 0; i <= numbers.GetUpperBound(0); i++)
sum = sum + numbers[i];
Sử dụng các phần tử của mảng
// Truy xuat mang: dung phat bieu foreach
int sum = 0;
foreach (int i in numbers)
sum = sum + i;

Ghi chú:
™ Truy xuất mảng dùng vòng lặp for với cận trên là
số phần tử, thuộc tính Length hoặc phương thức
GetUpperBound( ): ta phải quan tâm đến số phần
tử của một mảng.
™ Truy xuất mảng dùng vòng lặp foreach: ta không
cần quan tâm đến số phần tử của một mảng.
Tìm kiếm tuần tự
™ Lớp CArray bao gồm các đối tượng là các
mảng có các thuộc tính và các phương thức
sau:
f Upper: cho biết cận trên của mảng.
f NumElements: cho biết số phần tử đang sử dụng
của mảng.
f Insert( ): thêm một phần tử mới vào cuối
mảng.
f Clear( ): xóa bỏ toàn bộ mảng (mảng rỗng).
f DisplayArray( ): hiển thị toàn bộ mảng.
f Swap( ): hoán đổi hai phần tử của mảng.
Tìm kiếm tuần tự
class CArray
{
private int[] Arr;
private int Upper;
private int NumElements;
public CArray(int size)
{
Arr = new int[size];
Upper = size – 1;
NumElements = 0;
}
public void Insert(int item)
{
Arr[NumElements] = item;
NumElements++;
}
Tìm kiếm tuần tự
public void DisplayArray( )
{
for (int i = 0; i < Arr.Length; i++)
Console.Write(Arr[i] + " ");
Console.WriteLine( );
}
public void Clear( )
{
for (int i = 0; i < Arr.Length; i++)
Arr[i] = 0;
NumElements = 0;
}
}
Tìm kiếm tuần tự
™ Phương pháp:
f Duyệt tuần tự một dãy a0,…, an-1 để tìm kiếm một
phần tử (lần gặp đầu tiên) có khóa tìm kiếm
(search key) là x.
f Kết thúc quá trình tìm kiếm khi tìm thấy một phần
tử có khóa x (tìm thấy) hoặc khi đã xét hết dãy
(không tìm thấy).
f Kết quả tìm kiếm: có hai cách
y Cách 1: Tìm thấy (true) hoặc không tìm thấy (false).
y Cách 2: Vị trí tìm thấy i >= 0 hoặc -1 (không tìm
thấy).
Tìm kiếm tuần tự
™ Nhận xét:
f Nếu dãy a0,…, an-1 có nhiều phần tử có cùng giá
trị của khóa tìm kiếm (khóa thứ cấp – secondary
key) thì trả về kết quả của lần gặp đầu tiên.
f Thời gian: T(n) = O(n)
Tìm kiếm tuần tự
searchNumber = 5
i
6 6 6 6
i
8 8 8 8
i
1 1 1 1
i
5 5 5 5
6 6 6 6
2 2 2 2
7 7 7 7
4 4 4 4
found = false found = false found = false found = true

Hình 5.1. Phương pháp tìm kiếm tuần tự


Tìm kiếm tuần tự
Giải thuật:
// Trả về kết quả tìm thấy hoặc không tìm tìm thấy
timthay = false;
ai là phần tử đầu tiên;
while (ai là phần tử của dãy && ! timthay)
if (ai = x)
timthay = true;
else
xét phần tử kế tiếp ai;
return timthay;
Tìm kiếm tuần tự
public bool SeqSearch(int searchKey)
{
bool found = false;
int i = 0;
while ((i < Arr.Length) && (! found))
if (Arr[i] == searchKey)
found = true;
else
i++;
return found;
}
Tìm kiếm tuần tự
Cách viết khác:
public bool SeqSearch(int searchKey)
{
for (int i = 0; i < Arr.Length; i++)
if (Arr[i] == searchKey)
return true;
return false;
}
Tìm kiếm tuần tự
Giải thuật:
// Trả về chỉ số của phần tử tìm thấy
vitri = -1;
timthay = false;
i = 0;
while (ai là phần tử của dãy && ! timthay)
if (ai = x)
{
timthay = true;
vitri = i;
}
else
xét phần tử kế tiếp ai;
return vitri;
Tìm kiếm tuần tự
public int SeqSearchAt(int searchKey)
{
bool found = false;
int position = -1;
int i = 0;
while ((i < Arr.Length) && (! found))
if (Arr[i] == searchKey)
{
found = true;
position = i;
}
else
i++;
return position;
}
Tìm kiếm tuần tự
Cách viết khác:
public int SeqSearchAt(int searchKey)
{
for (int i = 0; i < Arr.Length; i++)
if (Arr[i] == searchKey)
return i;
return -1;
}
Tìm kiếm tuần tự
using System;
public class Tester
{
static void Main( )
{
const int NMAX = 10;
CArray theArray = new CArray(NMAX);
Random rnd = new Random(100);
for (int i = 0; i < NMAX; i++)
theArray.Insert((int)(rnd.NextDouble( ) * 100));
theArray.DisplayArray( );
Console.Write("Nhap vao khoa can tim: ");
int searchKey =
Convert.ToInt32(Console.ReadLine( ), 10);
Tìm kiếm tuần tự
bool found = theArray.SeqSearch(searchKey);
if (found)
Console.WriteLine(“Tim thay khoa {0}”,
searchKey);
else
Console.WriteLine(“Khong tim thay khoa {0}”,
searchKey);
}
}
Tìm kiếm tuần tự
using System;
public class Tester
{
static void Main( )
{
const int NMAX = 10;
CArray theArray = new CArray(NMAX);
Random rnd = new Random(100);
for (int i = 0; i < NMAX; i++)
theArray.Insert((int)(rnd.NextDouble( ) * 100));
theArray.DisplayArray( );
Console.Write("Nhap vao khoa can tim: ");
int searchKey =
Convert.ToInt32(Console.ReadLine( ), 10);
Tìm kiếm tuần tự
int pos = theArray.SeqSearchAt(searchKey);
if (pos == -1)
Console.WriteLine(“Khong tim thay khoa {0}”,
searchKey);
else
Console.WriteLine(“Tim thay khoa {0} tai chi muc
{1}”, searchKey, pos);
}
}
Tìm kiếm tuần tự
public int FindMin( )
{
// Tìm giá trị nhỏ nhất của một dãy
int min = Arr[0];
for (int i = 0; i < Arr.Length; i++)
if (Arr[i] < min)
min = Arr[i];
}

public int FindMax( )


{
// Tìm giá trị lớn nhất của một dãy
int max = Arr[0];
for (int i = 0; i < Arr.Length; i++)
if (Arr[i] > max)
max = Arr[i];
}
Tìm kiếm tuần tự
Giải thuật:
// Dãy có thứ tự tăng dần (không giảm)
// Trả về kết quả tìm thấy hay không
ai là phần tử đầu tiên;
timthay = false;
while (ai là phần tử của dãy && ! timthay)
if (ai < x)
xét phần tử kế tiếp ai;
else if (ai = x)
timthay = true;
else
đã xét hết dãy;
return timthay;
Tìm kiếm tuần tự
searchNumber = 3
i
1 1 1 1
i
2 2 2 2
i
4 4 4 4
5 5 5 5
6 6 6 6
6 6 6 6
7 7 7 7
8 8 8 8
i
found = false found = false found = false not found

Hình 5.2. Phương pháp tìm kiếm tuần tự (dãy có thứ tự)
Tìm kiếm tuần tự
public bool SeqSearch(int searchKey)
{
// Day arr co thu tu tang dan
bool found = false;
int i = 0;
while ((i < Arr.Length) && (! found))
if (Arr[i] < searchKey)
i++
else if (Arr[i] = searchKey)
found = true;
else
i = Arr.Length;
return found;
}
Tìm kiếm tuần tự
public int SeqSearch(int searchKey)
{
// Day arr co thu tu tang dan
bool found = false;
int position = -1;
int i = 0;
while ((i < Arr.Length) && (! found))
if (Arr[i] < searchKey)
i++
else if (Arr[i] = searchKey)
{
found = true;
position = i;
}
else
i = Arr.Length;
return position;
}
Cấu trúc dữ liệu và Giải thuật
Chương 2: Mảng
37
Tìm kiếm nhị phân
™ Phương pháp:
f Chọn phần tử ở chính giữa là ak của dãy ai,…, aj
(đã có thứ tự tăng dần).
f Nếu x < ak: tìm x trong nửa đầu của dãy là ai,…,
ak-1.
f Nếu ak = x: tìm thấy phần tử ak. Kết thúc.
f Nếu ak < x: tìm x trong nửa cuối của dãy là ak+1,…,
aj.
f Kết quả tìm kiếm: có hai cách
y Cách 1: Tìm thấy (true) hoặc không tìm thấy (false).
y Cách 2: Vị trí tìm thấy i >= 0 hoặc -1 (không tìm
thấy).
Cấu trúc dữ liệu và Giải thuật
Chương 2: Mảng
38
Tìm kiếm nhị phân
™ Nhận xét:
f Dãy a0,…, an-1 phải có thứ tự tăng dần.
f Thời gian: T(n) = O(log2n)
Tìm kiếm nhị phân
searchNumber = 2 lowerBound
upperBound
1 2 4 5 6 6 7 9 5>2
mid

1 2 4 2=2

1 2 4 found

Hình 5.3. Phương pháp tìm kiếm nhị phân (tìm thấy)
Tìm kiếm nhị phân
searchNumber = 8
lowerBound
1 2 4 5 6 6 7 9 5<8 upperBound
mid
6 6 7 9 6<8

7 9 7<8

9 9>8

not found

Hình 5.4. Phương pháp tìm kiếm nhị phân (không tìm thấy)
Tìm kiếm nhị phân
Giải thuật:
// Dãy a0,…, an-1 đã có thứ tự tăng dần
i = 0;
j = n - 1;
timthay = false;
while (tồn tại dãy ai,…, aj && ! timthay)
{
ak là phần tử ở chính giữa;
if (x < ak)
tìm x trong nửa đầu của dãy là ai,…, ak-1;
else if (ai = x)
timthay = true;
else
tìm x trong nửa cuối của dãy là ak+1,…, aj;
}
return timthay;
Tìm kiếm nhị phân
public bool BinSearch(int searchKey)
{
bool found = false;
int i = 0;
int j = Arr.Length – 1;
while ((i <= j) && (! found))
{
int k = (i + j) / 2;
if (searchKey < Arr[k])
j = k – 1;
else if (Arr[k] == searchKey)
found = true;
else
i = k + 1;
}
return found;
}
Tìm kiếm nhị phân
public int BinSearchAt(int searchKey)
{
bool found = false;
int i = 0;
int j = Arr.Length – 1;
int position = -1;
while ((i <= j) && (! found))
{
int k = (i + j) / 2;
if (searchKey < Arr[k])
j = k – 1;
else if (Arr[k] == searchKey)
{
found = true;
position = k;
}
Tìm kiếm nhị phân
else
i = k + 1;
}
return position;
}
Tìm kiếm nhị phân
public int BinSearch(int searchKey)
{
int i = 0;
int j = Arr.Length – 1;
while (i <= j)
{
int k = (i + j) / 2;
if (searchKey < Arr[k])
j = k – 1;
else if (Arr[k] == searchKey)
return k;
else
i = k + 1;
}
return -1;
}
Tìm kiếm nhị phân
Giải thuật:
// Giải thuật đệ qui
public int RBinSearchAt(x, i, j)
{
if (không tồn tại dãy ai,…, aj)
return -1;
else
{
ak là phần tử ở chính giữa;
if (x < ak)
RBinSearchAt(x, i, k-1);
else if (ai = x)
return k;
else
RBinSearchAt(x, k+1, j);
}
}
Tìm kiếm nhị phân
public int RBinSearchAt(int searchKey, int i, int j)
{
// Giai thuat de qui
if (i > j)
return -1;
else
{
int k = (i + j) / 2;
if (searchKey < Arr[k])
return RBinSearchAt(searchKey, i, k – 1);
else if (searchKey == Arr[k])
return k;
else
return RBinSearchAt(searchKey, k + 1, j);
}
}
Tìm kiếm nhị phân
public int RBinSearch(int searchKey)
{
return RBinSearchAt(searchKey, 0, Arr.Length - 1);
}
Tìm kiếm nhị phân
static void Main( )
{
const int NMAX = 10;
CArray theArray = new CArray(NMAX);
Random random = new Random(100);
for (int i = 0; i < NMAX; i++)
theArray.Insert((int)(rnd.NextDouble() * 100));
theArray.QuicSort( );
theArray.DisplayArray( );
int position = theArray.RBinSearch(20);
if (position > -1)
Console.WriteLine(“ found item”);
else
Console.WriteLine(“ not found”);
Console.Read( );
}
Tổng kết
™ Nắm vững định nghĩa mảng.
™ Cách khai báo kiểu và khởi tạo một biến kiểu
mảng.
™ Cách sử dụng các phần tử của mảng bằng chỉ
mục.
Tổng kết
™ Tìm kiếm tuần tự: bắt đầu tìm kiếm từ phần tử
đầu tiên. Độ phức tạp của giải thuật là O(n). Có
hai trường hợp:
f Dãy chưa có thứ tự: phải duyệt hết dãy trong
trường hợp không tìm thấy khóa cần tìm.
f Dãy đã có thứ tự: có thể không duyệt hết dãy
trong trường hợp không tìm thấy khóa cần tìm.
™ Tìm kiếm nhị phân: dãy phải có thứ tự (tăng
dần / giảm dần). Độ phức tạp của giải thuật là
O(log2n). Mỗi bước lặp chỉ tìm kiếm khoá cần
tìm trong nửa dãy đầu hoặc nửa dãy cuối.
Cấu trúc dữ liệu và Giải thuật
Chương 2: Mảng
52

You might also like