Chương 2 (1) : Giải Thuật Tìm Kiếm

Giảng viên : Nguyễn Minh Thành Email : thanhnm@itc.edu.vn

Nội Dung I. Giới thiệu II. Giải thuật tìm kiếm III. Tìm kiếm tuyến tính IV. Tìm kiếm nhị phân

Nguyễn Minh Thành

2

I. Giới Thiệu  Tìm kiếm : là duyệt một danh sách và lấy ra phần tử thoả tiêu

chuẩn cho trước

 Là một thao tác phổ biến trên máy tính và trong các ứng dụng

 Tìm kiếm 1 dòng trong CSDL  Tìm kiếm hồ sơ, tập tin  Tìm kiếm 1 người trong một danh sách  …

 Việc tìm kiếm nhanh thông tin trong một lượng lớn thông tin là

một điều cần thiết. Các giải thuật tìm kiếm

Nguyễn Minh Thành

3

II. Giải thuật tìm kiếm  Khảo sát việc tìm kiếm thường trên mảng và danh sách.  Có nhiều loại :

 Tìm kiếm tuyến tính (tuần tự)  Tìm kiếm nhị phân  …

 Cấu trúc :  Input

 Mảng A gồm n phần tử  Giá trị x cần tìm

 Output

 Vị trí x trong A hoặc -1 nếu không tồn tại x

4

 Thao tác cơ bản

 So sánh Nguyễn Minh Thành

III. Tìm Kiếm Tuyến Tính  Có 2 loại tìm kiếm tuyến tính :

Nguyễn Minh Thành

5

 Vét cạn (exhaustive)  Dùng lính canh (sentinel)

III. Tìm Kiếm Tuyến Tính – Vét Cạn  Thuật toán :

 Lần lượt so sánh x với các phần tử của mảng A cho đến khi

gặp được phần tử cần tìm, hoặc hết mảng.

Nguyễn Minh Thành

6

 Ví dụ: A = {1, 25, 6, 5, 2, 37, 40}, x = 6

III. Tìm Kiếm Tuyến Tính – Vét Cạn  Cài đặt 1 :

int LinearExhaustive(int a[], int N, int x) {

int i=0; while ((i

i++; if(i==N)

return -1;// tìm hết mảng nhưng không có x

else

return i;// a[i] là phần tử có khoá x

Nguyễn Minh Thành

7

}

III. Tìm Kiếm Tuyến Tính – Vét Cạn  Cài đặt 2 :

int LinearExhaustive(intA[], intn, intx) {

for(int i=0; i

if(A[i]==x)

return i;

return -1;

}

Nguyễn Minh Thành

8

III. Tìm Kiếm Tuyến Tính – Vét Cạn  Phép so sánh là phép toán sơ cấp được dùng trong thuật toán-> số lượng các phép so sánh sẽ là thước đo độ phức tạp của thuật toán.

 Mỗi vòng lặp có 2 điều kiện cần kiểm tra:

 Kiểm tra cuối mảng  Kiểm tra phần tử hiện tại có bằng x hay không?

 Trường hợp xấu nhất nằm ở cuối mảng A

 Ta có 2*n+1 số phép so sánh

Nguyễn Minh Thành

9

 => Số phép so sánh tăng/giảm tuyến tính theo số phần tử  Vậy độ phức tạp của thuật toán là : O(n)

III. Tìm Kiếm Tuyến Tính – Lính Căn  Trong thuật toán vét cạn, có 2 điều kiện được kiểm tra:

 Có thể bỏ việc kiểm tra điều kiện cuối mảng bằng cách dùng

“lính canh”.

 Lính canh là phần tử có giá trị bằng với phần tử cần tìm và đặt

ở cuối mảng.  Thuật toán lính căn

Nguyễn Minh Thành

10

III. Tìm Kiếm Tuyến Tính – Lính Căn  Thuật toán lính căn

 Tìm tuần tự từ đầu mảng cho đến khi tìm thấy x (chắc chắn sẽ

tìm thấy x)

 Nếu x được tìm thấy tại vị trí lính canh thì x không thuộc mảng

A.

Nguyễn Minh Thành

11

 Ngược lại trả về vị trí của x trong mảng A.

III. Tìm Kiếm Tuyến Tính – Lính Căn  Cài đặt 1 :

int LinearSentinel(int a[],int N,int x) {

int i=0; // mảng gồm N phần tử từ a[0]..a[N-1] a[N] = x; // thêm phần tử thứ N+1

while (a[i]!=x ) i++;

if (i==N)

return -1; // tìm hết mảng nhưng không có x

else

return i; // tìm thấy x tại vị trí i

Nguyễn Minh Thành

12

}

III. Tìm Kiếm Tuyến Tính – Lính Căn  Cài đặt 2 :

int LinearSentinel(int a[], int n, int x) {

a[n] = x; //đặtlínhcanh

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

if (a[i] == x) break;

if(i==n) i=-1;

return i;

Nguyễn Minh Thành

13

}

III. Tìm Kiếm Tuyến Tính – Lính Căn  Số phép so sánh trong trường hợp xấu nhất : n+2  Vậy độ phức tạp của thuật toán là O(n)  Tuy nhiên, thực nghiệm cho thấy trong trường hợp n lớn, thời gian

tìm kiếm giảm khi dùng phương pháp lính canh.

Nguyễn Minh Thành

14

 Với n=15000: nhanh hơn khoảng 20% (0.22s so với 0.28s)

IV. Tìm Kiếm Nhị Phân  Khi một mảng đã được sắp thứ tự, tận dụng điều này ta có thể giảm

một số thao tác cho thuật toán tìm kiếm.

 Thuật toán tìm kiếm nhị phân

 Input:

 Dãy A, n phần tử đã được sắp xếp  Giá trị x cần tìm

Nguyễn Minh Thành

15

 Output: giống với thuật toán tìm kiếm tuần tự

IV. Tìm Kiếm Nhị Phân  Ý tưởng

 So sánh x với phần tử chính giữa mảng A.  Nếu x là phần tử giữa thì dừng.

Nếu không : xác định xem x có thể thuộc nửa trái hay nửa phải của A.

Nguyễn Minh Thành

16

 Lặp lại 2 bước trên với nửa đã được xác định.

IV. Tìm Kiếm Nhị Phân  Ví dụ : tìm x = 41

x

x

x

14 14 14 14

16 16 16 16

19 19 19 19

3 3 3 3

51 51 51 51

46 46 46 46

63 63 63 63

71 71 71 71

22 22 22 22

41 41 41 41

2 2 2 2

3 3 3 3

4 4 4 4

1 1 1 1

8 8 8 8

7 7 7 7

9 9 9 9

10 10 10 10

5 5 5 5

6 6 6 6

Tìm thấy x tại vị trí 6

l

m

r

m

m

Nguyễn Minh Thành

17

IV. Tìm Kiếm Nhị Phân  Ví dụ : tìm x = 45

x

x

x

x

14 14 14 14 14

16 16 16 16 16

19 19 19 19 19

3 3 3 3 3

51 51 51 51 51

63 63 63 63 63

71 71 71 71 71

22 22 22 22 22

41 41 41 41 41

46 46 46 46 46

2 2 2 2 2

3 3 3 3 3

4 4 4 4 4

1 1 1 1 1

8 8 8 8 8

9 9 9 9 9

10 10 10 10 10

5 5 5 5 5

6 6 6 6 6

7 7 7 7 7

l

m

r

m

l > r: Kết thúc: Không tìm thấy

m

m

Nguyễn Minh Thành

18

// tìm kiếm trên tất cả các phần tử

IV. Tìm Kiếm Nhị Phân  Các bước của giải thuật Bước 1: left = 1; right = N; Bước 2:

// lấy mốc so sánh

mid = (left+right)/2; So sánh a[mid] với x, có 3 khả năng : a[mid] = x: Tìm thấy. Dừng a[mid] > x: //tìm tiếp x trong dãy con aleft .. amid -1

a[mid] < x:

right =mid - 1;

//tìm tiếp x trong dãy con amid +1 .. aright

left = mid + 1;

Bước 3:

//còn phần tử chưa xét tìm tiếp.

Nếu left <= right Lặp lại Bước 2.

Nguyễn Minh Thành

19

Ngược lại: Dừng //Ðã xét hết tất cả các phần tử.

IV. Tìm Kiếm Nhị Phân  Cài đặt 1

int BinarySearch(int a[],int N,int x )

{

int left =0; right = N-1; int mid; do{

mid = (left + right)/2; if (x == a[mid])

return mid;//Thấy x tại mid

else if (x < a[mid])

right = mid -1;

else

left = mid +1;

}while (left <= right); return -1; // Tìm hết dãy mà không có x

Nguyễn Minh Thành

20

}

IV. Tìm Kiếm Nhị Phân  Cài đặt 2 (đệ quy)

int BinarySearch(int a[], int l, int r, int x) {

if(r < l) return -1; m = (l + r) / 2; if ( x < a[m])

BS(a,l,m-1,x);

else if (x > a[m])

BS(a,m+1,r,x);

return m; //là phần tửchính giữa

}

Nguyễn Minh Thành

21

IV. Tìm Kiếm Nhị Phân  Trường hợp xấu nhất là x nằm ở cuối mảng, số phép so sánh phải

thực hiện là : log2n + 1

 Vậy độ phức tạp của thuật toán : O(log2n)  Một số so sánh :

Nguyễn Minh Thành

22

 Tuy nhiên, mảng phải được sắp xếp trước.

Hỏi Đáp

Nguyễn Minh Thành

23