Thuật toán tìm kiếm
Đã giới thiệu| English | Ý nghĩa |
|---|---|
| linear search/ˈlɪnɪə sɜːtʃ/ | tìm kiếm tuyến tính |
| binary search/ˈbaɪnəri sɜːtʃ/ | tìm kiếm nhị phân |
Hai mươi câu hỏi cho một triệu cái tên
- Một cuốn điện thoại chứa một triệu cái tên. Kiểm tra từng cái một, bạn sẽ cần trung bình năm trăm nghìn phép so sánh trước khi tìm thấy cái mình muốn.
- Thay vào đó, mở ở giữa, quyết định tên nằm ở nửa nào, rồi bỏ đi nửa còn lại. Lặp lại. Bạn sẽ tìm thấy bất kỳ tên nào trong hai mươi phép so sánh.
- Năm trăm nghìn so với hai mươi không phải là sự tiết kiệm nhỏ; đó là sự khác biệt giữa một chương trình hoạt động được và một chương trình không dùng được. Và giá phải trả chỉ là một thứ: danh sách phải được sắp xếp sẵn.
- Bài học này về tìm kiếm tuyến tính và tìm kiếm nhị phân, hiệu suất của từng loại và cách lựa chọn.
Tìm kiếm tuyến tính
FOR i ← 1 TO n
IF A[i] = target THEN
RETURN i
ENDIF
NEXT i
RETURN -1 // not found
- Nó duyệt từ đầu đến cuối, so sánh từng phần tử với mục tiêu, và dừng lại khi tìm thấy hoặc chạm đến cuối danh sách.
- Nó hoạt động trên bất kỳ danh sách nào, đã sắp xếp hay chưa, và trên mọi cấu trúc dữ liệu có thể duyệt qua từng bước.
- Trường hợp xấu nhất: mục tiêu nằm ở cuối hoặc không tồn tại, nên tất cả $n$ phần tử đều được so sánh, tức là $O(n)$. Trung bình thì khoảng một nửa.

Kiểm tra từng cái một, bắt đầu từ đầu
Một tìm kiếm tuyến tính:
Difficulty 1/5 · 100 coins + a small bonus on first completion today
Tìm kiếm tuyến tính không cần chuẩn bị trước và hoạt động trên mọi danh sách, trường hợp xấu nhất là O(n).
Tìm kiếm tuyến tính là lựa chọn tốt hơn khi dữ liệu:
Difficulty 1/5 · 100 coins + a small bonus on first completion today
Với không có thứ tự để khai thác (hoặc danh sách rất nhỏ), tìm kiếm tuyến tính tránh chi phí sắp xếp trước.
Tìm kiếm nhị phân
low ← 1 ; high ← n
WHILE low <= high DO
mid ← (low + high) DIV 2
IF A[mid] = target THEN
RETURN mid
ENDIF
IF A[mid] < target THEN
low ← mid + 1
ELSE high ← mid - 1
ENDWHILE
RETURN -1
- Nó yêu cầu dữ liệu phải được sắp xếp. So sánh phần tử ở giữa với mục tiêu: nếu khớp thì dừng; nếu mục tiêu lớn hơn thì loại bỏ nửa dưới; ngược lại thì loại bỏ nửa trên.
- Mỗi phép so sánh cắt đôi phạm vi cần tìm, nên số phép so sánh là $O(\log_2 n)$.
- Đó là lý do một triệu phần tử cần khoảng hai mươi phép so sánh: $2^{20}$ lớn hơn một chút so với một triệu.
Thuật toán tìm kiếm
tìm kiếm nhị phân chia đôi phạm vi mỗi bước
Tìm kiếm tuyến tính kiểm tra từng mục; tìm kiếm nhị phân chia đôi danh sách đã sắp xếp — ít phép so sánh hơn nhiều.
Độ phức tạp thời gian trường hợp xấu nhất của tìm kiếm nhị phân là:
Difficulty 1/5 · 100 coins + a small bonus on first completion today
Việc chia đôi khoảng mỗi bước cho số phép so sánh theo logarit.
Khoảng bao nhiêu phép so sánh cần thiết cho tìm kiếm nhị phân với một triệu phần tử đã sắp xếp?
Difficulty 2/5 · 140 coins + a small bonus on first completion today
$\log_2(1\,000\,000) \approx 20$ — khoảng 20 phép so sánh.
Tìm kiếm nhị phân có thể áp dụng cho mọi danh sách, đã sắp xếp hay chưa.
Difficulty 1/5 · 100 coins + a small bonus on first completion today
Nó quyết định loại bỏ nửa nào bằng cách so sánh với phần tử ở giữa, điều này chỉ có ý nghĩa nếu dữ liệu đã được sắp xếp.
Tìm kiếm nhị phân có độ phức tạp O(log n) vì mỗi phép so sánh ____ phạm vi còn lại cần tìm kiếm.
Difficulty 1/5 · 100 coins + a small bonus on first completion today
Hai mươi lần chia đôi giảm một triệu xuống còn một, đó là lý do tại sao 2^20 hơi vượt quá một triệu là con số cần nhớ.
Ví dụ giải chi tiết: truy vết tìm kiếm nhị phân
- Danh sách đã sắp xếp là 2, 5, 8, 12, 16, 23, 38, 56, 72, 91. Hãy truy vết việc tìm kiếm số 23.
lowlà 1,highlà 10, nênmidlà 5, chứa giá trị 16. 16 nhỏ hơn 23, nên loại bỏ nửa dưới:lowtrở thành 6.lowlà 6,highlà 10, nênmidlà 8, chứa giá trị 56. 56 lớn hơn 23, nênhightrở thành 7.low6,high7, do đómidlà 6, giữ 23. Đã tìm thấy, trong ba lần so sánh mà tìm kiếm tuyến tính sẽ tốn sáu bước.- Hiển thị
low,high,midvà giá trị tương ứng tại mỗi bước. Phần lớn điểm số nằm ở phần truy vết, không phải đáp án cuối cùng.
Trong danh sách đã sắp xếp 2, 5, 8, 12, 16, 23, 38, 56, 72, 91, tìm kiếm nhị phân cần bao nhiêu phép so sánh để tìm thấy 23?
Difficulty 2/5 · 140 coins + a small bonus on first completion today
mid 5 chứa 16 (quá nhỏ), mid 8 chứa 56 (quá lớn), mid 6 chứa 23. Tìm kiếm tuyến tính sẽ mất sáu phép so sánh.
Chọn giữa hai loại
| Tuyến tính | Nhị phân | |
|---|---|---|
| dữ liệu phải sắp xếp | Không | Có |
| số lần so sánh, trường hợp xấu nhất | $n$ | $\log_2 n$ |
| một triệu mục | lên đến 1,000,000 | khoảng 20 |
| phù hợp với | Danh sách không sắp xếp hoặc nhỏ, danh sách liên kết | Mảng đã sắp xếp lớn, tìm kiếm nhiều lần |
- Sắp xếp ban đầu tốn kém hơn một lần tìm kiếm tuyến tính, nên tìm kiếm nhị phân chỉ có lợi thế khi danh sách đã sắp xếp sẵn hoặc sẽ được tìm kiếm rất nhiều lần.
- Tìm kiếm nhị phân cũng cần truy cập trực tiếp đến phần tử ở giữa, điều mà mảng có nhưng danh sách liên kết không có.
Ví dụ minh họa: lập luận cho lựa chọn
- Một chương trình tìm kiếm một danh sách không sắp xếp gồm 50 bản ghi đúng một lần. Tìm kiếm tuyến tính: việc sắp xếp danh sách trước sẽ tốn kém hơn nhiều so với 50 phép so sánh mà việc tìm kiếm cần thiết.
- Một chương trình tìm kiếm một mảng đã sắp xếp gồm một triệu bản ghi hàng ngàn lần mỗi giây. Tìm kiếm nhị phân: dữ liệu đã sắp xếp sẵn và mỗi lần tìm kiếm chỉ tốn khoảng 20 phép so sánh thay vì tối đa một triệu.
- Một chương trình tìm kiếm trên danh sách liên kết. Tìm kiếm tuyến tính: tìm kiếm nhị phân cần nhảy thẳng đến phần tử ở giữa, nhưng danh sách liên kết chỉ có thể duyệt từ đầu.
- Tên thuật toán, sau đó là tính chất của dữ liệu quyết định việc lựa chọn đó.
Gắn mỗi phương pháp tìm kiếm với các đặc điểm chính của nó.
Difficulty 2/5 · 140 coins + a small bonus on first completion today
Tìm kiếm nhị phân nhanh hơn nhiều (O(log n)) nhưng chỉ trên dữ liệu đã sắp xếp; tìm kiếm tuyến tính hoạt động ở đâu cũng được với O(n).
Khi nào tìm kiếm tuyến tính là lựa chọn tốt hơn? Chọn tất cả các đáp án đúng.
Difficulty 2/5 · 140 coins + a small bonus on first completion today
Trường hợp cuối cùng chính là nơi tìm kiếm nhị phân chiến thắng. Sắp xếp trước tốn kém hơn một lần tìm kiếm tuyến tính đơn lẻ, nên chỉ kinh tế khi thực hiện nhiều lần tìm kiếm.
Chi phí duy trì file đã sắp xếp
- Tìm kiếm nhị phân chỉ khả dụng trên danh sách đã sắp xếp, và việc sắp xếp đó không miễn phí. Một câu hỏi yêu cầu bạn justifying (giải thích) một lựa chọn đang yêu cầu bạn định giá chi phí đó.
- Nếu dữ liệu được tìm kiếm thường xuyên và thay đổi hiếm, hãy sắp xếp nó một lần và mọi lần tìm kiếm sau sẽ là $\log_2 n$. Đó là trường hợp của từ điển hoặc bảng tra cứu.
- Nếu dữ liệu thay đổi liên tục, mỗi lần chèn đều phải giữ nguyên thứ tự, điều này tốn chi phí di chuyển các phần tử phía sau. Khi đó, tìm kiếm tuyến tính trên dữ liệu không sắp xếp có thể có tổng chi phí thấp hơn.
- Các con số giúp lập luận cụ thể: một triệu bản ghi cần tối đa một triệu lần so sánh theo phương pháp tuyến tính, nhưng chỉ 20 theo tìm kiếm nhị phân, bởi vì $2^{20} > 10^6$.
- Vì vậy, câu trả lời được chấm điểm cần nêu cả hai yếu tố: tần suất tìm kiếm và tần suất thay đổi.
Sắp xếp lý do chọn thuật toán tìm kiếm theo thứ tự.
Difficulty 3/5 · 200 coins + a small bonus on first completion today
Câu hỏi về lý do muốn thấy sự đánh đổi, chứ không phải người thắng cuộc. Tìm kiếm nhị phân trên danh sách thay đổi liên tục có thể tốn tổng chi phí cao hơn tìm kiếm tuyến tính.
Điểm số dễ mất
- Tìm kiếm nhị phân yêu cầu dữ liệu đã được sắp xếp. Nói "nó nhanh hơn" mà không có điều kiện này sẽ bị mất điểm.
- Mỗi bước giảm một nửa phạm vi, đó là nguồn gốc của $\log_2 n$. Hãy đưa ra lý do, không chỉ ký hiệu.
- Cả hai tìm kiếm đều phải có khả năng báo cáo không tìm thấy, đây chính là mục đích của
-1và điều kiện vòng lặp. - Tìm kiếm nhị phân cần truy cập trực tiếp, nên nó không áp dụng cho danh sách liên kết ngay cả khi danh sách đó đã được sắp xếp.
Bạn đã nắm vững
- Tìm kiếm tuyến tính so sánh từng phần tử từ đầu, hoạt động trên bất kỳ danh sách nào, và là $O(n)$
- Tìm kiếm nhị phân cần dữ liệu đã sắp xếp với truy cập trực tiếp, so sánh phần tử ở giữa và giảm một nửa phạm vi mỗi lần, tạo ra $O(\log_2 n)$: khoảng 20 phép so sánh cho một triệu phần tử
- Theo dõi tìm kiếm nhị phân bằng cách hiển thị
low,high,midvà giá trị tại mỗi bước - Chọn từ dữ liệu: không sắp xếp, nhỏ hoặc là danh sách liên kết thì dùng tìm kiếm tuyến tính; lớn, đã sắp xếp và tìm kiếm thường xuyên thì dùng tìm kiếm nhị phân