Chương 2.1. Giải thuật tìm kiếm
1
2
*
Xác định được vai trò của tìm kiếm và sắp
xếp trong hệ thống thông tin
*
Nắm vững và minh họa được giải thuật tìm
kiếm tuyến tính và tìm kiếm nhị phân trên
mảng một chiều
*
Cài đặt được giải thuật tìm kiếm bằng ngôn
ngữ C/C++
3
Hãy liệt kê những phần mềm trên
máy tính có dùng chức năng tìm kiếm và sắp
xếp?
?
4
*
Thao tác tìm kiếm được sử dụng nhiều nhất trong
các hệ lưu trữ và quản lý dữ liệu.
*
Do dữ liệu lớn nên tìm ra giải thuật tìm kiếm
nhanh chóng là mối quan tâm hàng đầu. Để đạt
được điều này dữ liệu phải được tổ chức theo một
thứ tự nào đó thì việc tìm kiếm sẽ nhanh chóng và
hiệu quả hơn, vì vậy nhu cầu sắp xếp dữ liệu cũng
được lưu ý.
*
Tóm lại, bên cạnh những giải thuật tìm kiếm thì
các giải thuật sắp xếp dữ liệu không thể thiếu
trong hệ quản lý thông tin trên máy tính.
5
*
Có 2 giải thuật thường được áp dụng: Tìm tuyến
tính và tìm nhị phân.
*
Để đơn giản cho việc minh họa, ta đặc tả như
sau:
*
Tập dữ liệu được lưu trữ là dãy số a
1
, a
2
, ,a
N
.
*
Giả sử chọn cấu trúc dữ liệu mảng để lưu trữ dãy
số này trong bộ nhớ chính, có khai báo: int a[N];
*
Khoá cần tìm là x, được khai báo như sau: int x;
a
1
a
2
a
3
a
4
a
5
… a
n-1
a
N
*
Ý tưởng
Tiến hành so sánh x lần lượt với phần tử thứ
nhất, thứ hai, của mảng a cho đến khi gặp
được phần tử có khóa cần tìm, hoặc đã tìm hết
mảng mà không thấy x.
*
Minh họa tìm x =10
*
Minh họa tìm x =25
Chưa hết
mảng
6
7 5 12 41 10 32 13 9 15 3
1 2 3 4 5 6 7 8 9 10
7 5 12 41 10 32 13 9 15 3
1 2 3 4 5 6 7 8 9 10
10
10
25
Chưa
hết
mảng
Đã tìm
thấy tại
vị trí 5
Đã hết
mảng
7
*
Giải thuật
Bước 1:
i = 1; // bắt đầu từ phần tử đầu tiên của
dãy
Bước 2: So sánh a[i] với x, có 2 khả năng :
*
a[i] = x : Tìm thấy. Dừng
*
a[i] != x : Sang Bước 3.
Bước 3:
*
i = i+1; // xét tiếp phần tử kế trong mảng
*
Nếu i >N: Hết mảng, không tìm thấy. Dừng
Ngược lại: Lặp lại Bước 2.
8
Cài đặt
int LinearSearch(int a[], int N, int x)
{
int i=0;
while ((i<N) && (a[i]!=x ))
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
}
9
Cải tiến (dùng lính canh) giúp giảm bớt một
phép so sánh
*
Minh họa tìm x =10
*
Minh họa tìm x = 25
7 5 12 41 10 32 13 9 15 3
1 2 3 4 5 6 7 8 9 10
10
10
7 5 12 41 10 32 13 9 15 3
1 2 3 4 5 6 7 8 9 10
25
11
25
25
10
11
10
Cài đặt
int LinearSearch2(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
}
Ðánh giá giải thuật
Độ phức tạp tính toán cấp n: T(n)=O(n)
11
Ý tưởng
*
Áp dụng đối với những dãy số đã có thứ tự.
*
Giải thuật tìm cách giới hạn phạm vi tìm kiếm
sau mỗi lần so sánh x với một phần tử trong
dãy. Ý tưởng của giải thuật là tại mỗi bước tiến
hành so sánh x với phần tử nằm ở vị trí giữa
của dãy tìm kiếm hiện hành, dựa vào kết quả
so sánh này để quyết định giới hạn dãy tìm
kiếm ở bước kế tiếp là nửa trên hay nửa dưới
của dãy tìm kiếm hiện hành.
12
Minh họa tìm x = 41
3 14 16 19 22 41 46 51 63 71
1 2 3 4 5 6 7 8 9 10
x
m
3 14 16 19 22 41 46 51 63 71
1 2 3 4 5 6 7 8 9 10
l m
x
3 14 16 19 22 41 46 51 63 71
1 2 3 4 5 6 7 8 9 10
r
m
x
3 14 16 19 22 41 46 51 63 71
1 2 3 4 5 6 7 8 9 10
Tìm thấy x tại
vị trí 6
13
Minh họa tìm x = 45
3 14 16 19 22 41 46 51 63 71
1 2 3 4 5 6 7 8 9 10
x
m
3 14 16 19 22 41 46 51 63 71
1 2 3 4 5 6 7 8 9 10
m
x
3 14 16 19 22 41 46 51 63 71
1 2 3 4 5 6 7 8 9 10
r
m
x
l
3 14 16 19 22 41 46 51 63 71
1 2 3 4 5 6 7 8 9 10
m
x
3 14 16 19 22 41 46 51 63 71
1 2 3 4 5 6 7 8 9 10
l > r: Kết thúc:
Không tìm thấy
14
Giải thuật
Bước 1: left = 1; right = N; // tìm kiếm trên tất
cả các phần tử
Bước 2:
mid = (left+right)/2; // lấy mốc so sánh
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 a
left
a
mid -1
right =mid - 1;
a[mid] < x: //tìm tiếp x trong dãy con a
mid +1
a
right
left = mid + 1;
Bước 3:
Nếu left <= right //còn phần tử chưa xét tìm
tiếp.
Lặp lại Bước 2.
Ngược lại: Dừng //Ðã xét hết tất cả các
phần tử.
15
Cài đặt
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
}
Ðánh giá giải thuật
Độ phức tạp tính toán cấp n: T(n)=O(log
2
n)
16
17
#include <iostream.h> #include<stdlib.h> #include<time.h>
#define MAX 1000
void TaoMang(int a[], int N);
void XuatMang(int a[], int N);
int LinearSearch(int a[], int N);
void main()
{ srand((usigned int) time (NULL));
int a[MAX], N = 20, x, kq;
TaoMang(a, N); XuatMang(a, N);
cout<<“Nhap gia tri can tim: “; cin>>x;
kq=LinearSearch(a, N, x);
if(kq==-1) cout<<“Khong co phan tu can tim”;
else cout<<“Phan tu can tim xuat hien tai vi tri: ”<<kq;
}
18
void TaoMang(int a[], int N)
{
for(int i=0; i<N; i++)
a[i]=rand()%N;
}
void XuatMang(int a[], int N)
{
for(int i=0; i<N; i++)
cout<<a[i]<<“ “;
}
19
int LinearSearch(int a[], int N, int x)
{
int i=0;
while ((i<N) && (a[i]!=x ))
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
}
20
*
LT1_1: Cho dãy số sau:
Cho biết vị trí tìm thấy và số lần so sánh để tìm
được phần tử có giá trị x = 6 khi áp dụng giải thuật
tìm kiếm: tuyến tính và nhị phân.
*
LT1_2: Xây dựng giải thuật tìm kiếm phần tử có
giá trị nhỏ nhất trong dãy số: Dùng mã giả và lưu
đồ.
3 4 6 6 12 16 21 34 41 80
0 1 2 3 4 5 6 7 8 9