Ý tưởng chính: duyệt tuần tự từ phần tử đầu tiên, lần lượt so sánh khĩa tìm kiếm với khố tương ứng của các phần tử trong danh sách (trong trường hợp mơ tả trên là so sánh x và a[i]). Cho đến khi gặp phần tử cần tìm hoặc đến khi duyệt hết danh sách.
Các bước tiến hành như sau : Bước 1: i = 1 ;
Bước 2: so sánh a[i] với x, cĩ hai khả năng i. a[i] = x: tìm thấy ⇒ dừng ii. a[i] <> x: sang bước 3
Bước 3: i = i +1, kiểm tra chỉ số i và kích thước mảng n i. nếu i>n: hết mảng, khơng tìm thấy ⇒ dừng ii. ngược lại: quay lại bước 2
Hàm tìm kiếm tuyến tính đơn giản minh họa bằng ngơn ngữ C/C++.
Tìm kiếm
Tìm kiếm
Tìm kiếm tuyến tính
Tìm kiếm tuyến tính Tìm kiếm nhị phânTìm kiếm nhị phân
Tập DL bất kỳ Tập DL được sắp x ? a1 a2 a3 an-1 an
int Search(int a[], int n, int key) {
int i =0;
while (i<n) && (key != a[i]) i++;
if (i >= n)
return -1; // tìm khơng thấy
else
return i; // tìm thấy tại vị trí i
}
1.1.3 Tìm kiếm nhị phân
Phương pháp tìm kiếm nhị phân được áp dụng cho dãy khố đã cĩ thứ tự: k[1] ≤
k[2] ≤ ... ≤ k[n].
Ý tưởng của phương pháp này như sau:
Giả sử ta cần tìm trong đoạn a[left...right] với khố tìm kiếm là x, trước hết ta xét phần tử giữa a[mid], với mid = (left + right)/2.
• Nếu a[mid] < x thì cĩ nghĩa là đoạn a[left] đến a[right] chỉ chứa khĩa < x, ta tiến hành tìm kiếm từ a[mid+1] đến a[right].
• Nếu a[mid] > x thì cĩ nghĩa là đoạn a[m] đến a[right] chỉ chứa khố > x, ta tiến hành tìm kiếm từ a[left] đến a[mid-1].
• Nếu a[mid] = x thì việc tìm kiếm thành cơng.
• Quá trình tìm kiếm thất bại nếu left > right. Các bước tiến hành như sau:
Bước 1: left =1, right = n // tìm kiếm trên tất 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 trong dãy a[left].. a[mid-1] right = mid -1;
- a[mid] < x, tìm tiếp trong dãy a[mid+1].. a[right] left = mid +1;
Bước 3:
Ngược lại: dừng, đã xét hết phần tử ⇒ khơng tìm thấy. Ví dụ: cho dãy số gồm 8 phần tử {1, 2, 4, 5, 6, 8, 12, 15} và x = 8
Hình 4.2: Tìm kiếm nhị phân. Hàm C minh họa cài đặt thuật tốn tìm kiếm nhị phân
int BinarySearch(int key) {
int left = 0, right = n-1, mid; while (left <= right)
{
mid = (left + right)/ 2; // lấy điểm giữa
if (a[mid] == key) // nếu tìm được
return mid;
if (a[mid] < x) // tìm đoạn bên phải mid
left = mid+1; else
right = mid-1; // tìm đoạn bên trái mid
}
return -1; // khơng tìm được
} 1 1 Left = 1 X = 8 X = 8 Right = 8 Mid = 4 Đoạn tìm kiếm 2 2 44 55 66 88 1212 1515 1 1 Left = 5 X = 8 X = 8 Right = 8 Mid = 6 Đoạn tìm kiếm 2 2 44 55 66 88 1212 1515 = =
1.1.4 Kết luận
• Giải thuật tìm kiếm tuyến tính khơng phụ thuộc vào thứ tự của các phần tử trong mảng, do vậy đây là phương pháp tổng quát nhất để tìm kiếm trên một dãy bất kỳ.
• Thuật giải nhị phân dựa vào quan hệ giá trị của các phần tử trong mảng để định hướng trong quá trình tìm kiếm, do vậy chỉ áp dụng được với dãy đã cĩ thứ tự.
• Thuật giải nhị phân tìm kiếm nhanh hơn tìm kiếm tuyến tính.
• Tuy nhiên khi áp dụng thuật giải nhị phân thì cần phải quan tâm đến chi phí cho việc sắp xếp mảng. Vì khi mảng được sắp thứ tự rồi thì mới tìm kiếm nhị phân.
1.2 Bài tốn sắp xếp
Sắp xếp là quá trình bố trí lại các phần tử của một tập đối tượng nào đĩ theo một thứ tự nhất định. Ví dụ như: tăng dần, giảm dần với một dãy số, thứ tự từ điển với các từ...Việc sắp xếp là một bài tốn thường thấy trong tin học, do các yêu cầu tìm kiếm thuận lợi, sắp xếp kết quả các bảng biểu...
Dữ liệu thường được tổ chức thành mảng các mẫu tin dữ liệu, mỗi mẫu tin thường cĩ một số các trường dữ liệu khác nhau. Khơng phải tồn bộ các trường đều tham gia quá trình sắp xếp mà chỉ cĩ một trường nào đĩ (hoặc một vài trường) được quan tâm. Người ta gọi trường này là khố, việc sắp xếp sẽ được tiến hành dựa vào giá trị khố này.
Ví dụ: sắp xếp một mảng các số nguyên tăng dần, sắp xếp một danh sách học sinh với điểm thi giảm dần...
1.3 Một số phương pháp sắp xếp cơ bản
Trong phần này giới thiệu một số phương pháp sắp xếp cơ bản thường được dùng để sắp xếp một danh sách, mảng dữ liệu.
1.3.1 Phương pháp chọn
Đây là một trong những thuật tốn sắp xếp đơn giản nhất. Ý tưởng cơ bản của phương pháp này được thể hiện như sau:
1. Ở lượt thứ nhất, ta chọn trong dãy khố k[1..n] ra khố nhỏ nhất và đổi giá trị nĩ với k[1], khi đĩ k[1] sẽ trở thành khố nhỏ nhất.
2. Ở lượt thứ hai, ta chọn trong dãy khố k[2..n] ra khĩa nhỏ nhất và đổi giá trị nĩ cho k[2].
3. ...
4. Ở lượt thứ i, ta chọn trong dãy khĩa k[i..n] ra khĩa nhỏ nhất và đổi giá trị nĩ cho k[i].
5. Tới lượt k-1, ta chọn giá trị nhỏ nhất trong k[n-1] và k[n] ra khố nhỏ nhất và đổi cho giá trị cho k[n-1].
Thuật giải SelectionSort: (mã giả, chỉ số 1 là đầu mảng)
begin
for i:= 1 to n-1 do begin
jmin := i;
for j:=i+1 to n do
if a[j] < a[jmin] then jmin = j; if ( jmin <> i) Swap(a[i], a[jmin]) end. end. 1.3.2 Phương pháp sắp xếp nổi bọt
Trong thuật tốn sắp xếp nổi bọt, dãy khĩa sẽ được duyệt từ cuối lên đầu dãy, nếu gặp hai khĩa kế cận ngược thứ tự thì đổi chỗ cho nhau. Sau lần duyệt như vậy, khĩa nhỏ nhất trong dãy khĩa sẽ được chuyển về vị trí đầu tiên và vấn đề trở thành sắp xếp dãy khố từ k[n] đến k[2].
Thuật giải bubblesort: (mả giả, chỉ số 1 là đầu mảng)
begin for i:=2 to n do for j:= n downto i do if (a[j] < a[j-1]) Swap(a[j],a[j-1]) end. 1.3.3 Phương pháp sắp xếp chèn
Xét dãy khĩa k[1..n], ta thấy dãy con chỉ gồm mỗi một khố là k[1] cĩ thể coi là đã sắp xếp rồi. Xét thêm k[2], ta so sánh nĩ với k[1], nếu thấy k[2] < k[1] thì chèn nĩ vào trước k[1]. Đối với k[3], ta chỉ xét dãy chỉ gồm hai khố k[1] và k[2] đã sắp xếp và tìm cách chèn k[3] vào dãy khĩa đĩ để được thứ tự sắp xếp. Một cách tổng quát, ta sẽ sắp
xếp dãy k[1..i] trong điều kiện dãy k[1..i-1] đã sắp xếp rồi bằng cách chèn k[i] vào dãy đĩ tại vị trí đúng khi sắp xếp.
Thuật giải InsertionSort: (mả giả, chỉ số 1 là đầu mảng)
begin
for i:= 2 to n do begin
tmp = a[i]; j = i-1;
while (j>0) and (tmp < a[j]) begin
a[j+1] = a[j];// đẩy lùi giá trị k[i] về sau -> tạo khoảng trống j := j-1;
end
k[j+1] = tmp; // chèn vào khoảng trống.
end end.