Professional Documents
Culture Documents
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
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};
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];
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.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