1. Đặt vấn đề:
Giả sử chúng ta cĩ một mảng M gồm N phần tử. Vấn đề đặt ra là cĩ hay khơng phần tử cĩ giá trị bằng X trong mảng M? Nếu cĩ thì phần tử cĩ giá trị bằng X là phần tử thứ mấy trong mảng M?
2. Tìm tuyến tính (Linear Search)
Thuật tốn tìm tuyến tính cĩn đƣợc gọi là thuật tốn tìm kiếm tuần tự (Sequential Search)
a. Ý tƣởng:
Lần lƣợt so sánh các phần tử của mảng M với các giá trị X bắt đầu tử phần từ đầu tiên cho đến khi tìm đến đƣợc phần tử cĩ giá trị X hoặc đã duyệt qua hết tất cả các phần tử của mảng M thì kết thúc.
b. Thuật tốn
B1: i = 1 //Duyệt từ đầu mảng
B2: IF M[i] ≠ X AND i ≤ N //Nếu chƣa tìm thấy và cũng chƣa duyệt hết mảng B2.1: i++
B2.2: Lập lại bƣớc 2 B3: IF i ≤ N
Tìm thấy tại vị trí i
B4: ELSE Khơng tìm thấy phần tử cĩ giá trị X B5: Kết thúc.
c. Cài đặt thuật tốn:
Hàm thực hiện việc tìm kiếm phần tử cĩ giá trị X trên mảng M cĩ N phần tử. Nếu tìm thấy, hàm trả về một số nguyên cĩ giá trị từ 0 đến N-1 là vị tƣơng ứng của phần tử tìm thấy. Trong trƣờng hợp ngƣợc lại, hàm trả về giá trị -1 (khơng tìm thấy). Nội dung của hàm nhƣ sau:
int LinearSearch(int M[], int N, int x) {
int i=0;
while(i<N && M[i]!=x) i++;
if (i<N) return i; // a[i] là phần tử cĩ khố x
return -1; // tìm hết mảng nhưng khơng cĩ x
}
d. Phân tích thuật tốn:
-Trƣờng hợp tốt nhất khi phần tử đầu tiên của mảng cĩ giá trị bằng X: Số phép gán: Gmin = 1
Số phép so sánh: Smin = 2 + 1 = 3
Số phép gán: Gmax = 1
Số phép so sánh: Smax = 2N +1 -Trung bình:
Số phép gán: Gavg = 1
Số phép so sánh: Savg = (3 +2N + 1): 2 = N + 2 II. Tìm kiếm nhị phân
Thuật tốn tìm kiếm tuyến tính tỏ ra đơn giản và thuận tiện trong trƣờng hợp số phần tử của dãy khơng lớn lắm. Tuy nhiên, khi số phần tử của dãy khá lớn, chẳng hạn chúng ta tìm kiếm tên một khách hàng trong một danh bạ điện thoại của một thành phố lớn theo thuật tốn tìm kiếm tuần tự thì quả thực mất rất nhiều thời gian. Trong thực tế, thơng thƣờng các phầnt ử của dãy đã cĩ một thứ thụ, do vậy thuật tốn tìm nhị phân sau đây sẽ rút ngắn đáng kể thời gian tìm kiếm trên dãy đã cĩ thứ tự. Trong thuật tốn này chúng ta giả sử các phần tử trong dãy cĩ thứ tự tăng dần, tức là các phần tử đứng trƣớc luơn cĩ giá trị nhỏ hơn hoặc bằng phần tử đứng sau nĩ. Khi đĩ, nếu X nhỏ hơn giá trị phần tử đứng ở giữa dãy (M[Mid] thì X chỉ cĩ thể tìm thấy ở đầu dãy và ngƣợc lại, nếu X lớn hơn phần tử M[Mid] thì X chỉ cĩ thể thấy ở phía sau dãy.
a. Tƣ tƣởng:
Phạm vi tìm kiếm ban đầu của chúng ta là từ phần tử đầu tiên của dãy (First =1) cho đến phần tử cuối cùng củ dãy (Last =N).
So sánh giá trị X với giá trị phần tử đứng ở giữa của dãy m là M[Mid]. Nếu X=M[Mid]: tìm thấy.
Nếu X<M[Mid]: Rút ngắn phạm vi tìm kiếm về nữa đầu của dãy M (Last =Mid -1) Nếu X>M[Mid]: Rút ngắn phạm vi tìm kiếm về nữa sau của dãy M (First=Mid+1) Lặp lại quá trình này cho đến khi tìm thấy phần tử cĩ giá trị X hoặc phạm vi tìm kiếm của chúng ta khơng cịn nữa (First>Last).
b. Thuật tốn B1: First =1 B2: Last = N B3: If (First>Last) // Hết phạm vi tìm kiếm B3.1: Khơng tìm thấy B3.2: Thực kiện Bkt. B4: Mid = (First + Last)/ 2 B5: IF (X = M[Mid]) B6: If (X<M[Mid]) B6.1: Last = Mid -1 B6.2: Lặp lại B3. B7: If (X< M[Mid]) B7.1: First = Mid +1 B7.2: Lặp lại B3. Bkt: Kết thúc. c. Cài đặt thuật tốn: Hàm BinarySearch cĩ prototype: Int BinarySearch(int M[], int N, int X);
Hàm thực hiện việc tìm kiếm phần tử cĩ giá trị X trong mảng M cĩ N phần tử đã cĩ thứ tự tăng. Nếu tìm thấy, hàm trả về một số nguyên cĩ giá trị từ 0 đến N-1 là vị trí tƣơng ứng của phần tử tìm thấy. Trong trƣờng hợp ngƣợc lại, hàm trả về giá trị -1 (khơng tìm thấy).
int BinarySearch(int a[],int n,int x ) {
int left =0, right = n-1, mid; while (left <= right)
{
m = (left + right)/2;
if (x == a[mid]) return m;//Tìm thấy x tại mid if (x<a[mid]) r = mid -1;
else l = mid +1; }
return -1;// trong dãy khơng cĩ x
}
d. Phân tích thuật tốn:
- Trƣờng hợp tốt nhất khi phần tử lở giữa của mảng cĩ giá trị bằng X: Số phép gán; Gmin =
Số phép gán so sánh: Smin =2
- Trƣờng hợp xấu nhất khi khơng tìm thấy phần tử nào cĩ giá trị bằng X: Số phép gán: Gmax=2log2N + 4 Số phép so sánh: Smax = 3log2N + 1. - Trung bình: Số phép gán: Gavg = log2N + 3.5 Số phép so sánh: Savg = ½(3log2N + 3). Ví dụ:
Giả sử ta cĩ dãy M gồm 10 phần tử cĩ khĩa nhƣ sau (N=10): 1 3 4 5 8 15 17 22 25 30
Trƣớc tiên ta thực hiện tìm kiếm phần tử cĩ giá trị X = 5 (tìm thấy).
Bây giờ ta thực hiện tìm kiếm phần tử cĩ giá trị X = 7 (khơng tìm thấy)
Kết quả sau 4 lần lặp (đệ quy) thuật tốn kết thúc. Lưu ý:
Thuật tốn tìm nhị phân chỉ cĩ thể vận dụng trong trƣờng hợp dãy/mảng đã cĩ thứ tữ. Trong trƣờng hợp tổng quát chúng ta chỉ cĩ thể áp dụng thuật tốn tìm kiếm tuần tự.
Các thuật tốn đệ quy cĩ thể ngắn gọn song tốn kém bộ nhớ để ghi nhận mà lệnh chƣơng trình (mỗi lần gọi đệ quy) khi chạy chƣơng trình, do vậy cĩ thể l2m cho chƣơng trình chạy chậm lại. trong thực tế, khi viết chƣơng trình nếu cĩ thể chúng ta nên sử dụng thuật tốn khơng đệ quy.
CHƢƠNG VI:
CÂY