Tìm kiếm trong mảng - Linear Search, Binary Search
Interactive Lesson Page

Tìm kiếm trong mảng: Linear Search, Binary Search & lỗi hay gặp

Bài học giúp học sinh hiểu bản chất tìm kiếm tuyến tính và tìm kiếm nhị phân, biết chọn đúng thuật toán, tránh nhầm điều kiện “mảng đã sắp xếp”, đồng thời luyện các dạng bài thường gặp trong thi lập trình.

Mục tiêu bài học

  • Hiểu cách tìm kiếm phần tử trong mảng bằng Linear SearchBinary Search.
  • Phân biệt khi nào dùng tìm kiếm tuyến tính, khi nào dùng tìm kiếm nhị phân.
  • Biết viết code C++ và Python cho các bài: tìm có/không, tìm vị trí, đếm số lần xuất hiện.
  • Tránh các lỗi hay gặp: dùng binary search khi mảng chưa sắp xếp, sai chỉ số, vòng lặp vô hạn.

1. Hai kiểu tìm kiếm cơ bản

Linear Search

Duyệt lần lượt từng phần tử từ trái sang phải. Gặp phần tử cần tìm thì kết luận tìm thấy.

Dùng được với mảng chưa sắp xếp O(n)
Ví dụ đời sống: tìm một quyển vở trong chồng sách lộn xộn, ta phải kiểm tra từng quyển.

Binary Search

Mỗi bước lấy phần tử giữa, so sánh với giá trị cần tìm rồi bỏ đi một nửa khoảng không cần xét.

Rất nhanh O(log n) Chỉ dùng khi mảng đã sắp xếp
Ví dụ đời sống: tìm một từ trong từ điển. Vì từ điển đã sắp xếp, ta mở gần giữa và thu hẹp dần.
Tiêu chí Linear Search Binary Search
Điều kiện dùng Mảng bất kỳ Bắt buộc mảng đã sắp xếp tăng/giảm rõ ràng
Độ phức tạp O(n) O(log n)
Dễ code? Dễ, ít lỗi Nhanh nhưng dễ sai biên l, r, mid
Dạng bài phù hợp Tìm trong dữ liệu nhỏ hoặc chưa sắp xếp Tìm kiếm trong mảng đã sort, tìm first/last, lower_bound

2. Linear Search - tìm kiếm tuyến tính

Ý tưởng: xét từng vị trí i. Nếu a[i] == x thì tìm thấy. Nếu duyệt hết mảng mà không thấy thì kết quả là -1.

Mô phỏng Linear Search

Mảng ví dụ: [4, 7, 2, 9, 7, 1], tìm x = 7.

Nhật ký

Sẵn sàng mô phỏng...
#include 
using namespace std;

int main() {
    int n, x;
    cin >> n >> x;

    vector a(n);
    for (int i = 0; i < n; i++) cin >> a[i];

    int pos = -1;
    for (int i = 0; i < n; i++) {
        if (a[i] == x) {
            pos = i;      // vị trí đầu tiên tìm thấy
            break;        // dừng lại vì đã tìm thấy
        }
    }

    if (pos == -1) cout << "Khong tim thay";
    else cout << "Tim thay tai vi tri " << pos;

    return 0;
}
n, x = map(int, input().split())
a = list(map(int, input().split()))

pos = -1
for i in range(n):
    if a[i] == x:
        pos = i
        break

if pos == -1:
    print("Khong tim thay")
else:
    print("Tim thay tai vi tri", pos)
Điểm dễ nhầm: Nếu đề yêu cầu vị trí theo kiểu “phần tử thứ mấy” thì có thể phải in pos + 1. Nếu đề yêu cầu chỉ số trong mảng C++/Python thì in pos.

3. Binary Search - tìm kiếm nhị phân

Binary Search chỉ đúng khi mảng đã được sắp xếp. Với mảng tăng dần: nếu a[mid] < x thì tìm bên phải; nếu a[mid] > x thì tìm bên trái.

Cảnh báo quan trọng: Không được dùng tìm kiếm nhị phân cho mảng chưa sắp xếp. Ví dụ [4, 1, 9, 2] không thể binary search trực tiếp.

Mô phỏng Binary Search

Mảng ví dụ: [1, 3, 5, 7, 9, 11, 13, 15], tìm x = 11.

Nhật ký

Sẵn sàng mô phỏng...
#include 
using namespace std;

int binary_search_pos(const vector& a, int x) {
    int l = 0, r = (int)a.size() - 1;

    while (l <= r) {
        int mid = l + (r - l) / 2;

        if (a[mid] == x) return mid;
        if (a[mid] < x) l = mid + 1;
        else r = mid - 1;
    }

    return -1;
}

int main() {
    int n, x;
    cin >> n >> x;

    vector a(n);
    for (int i = 0; i < n; i++) cin >> a[i];

    int pos = binary_search_pos(a, x);
    cout << pos;

    return 0;
}
def binary_search_pos(a, x):
    l, r = 0, len(a) - 1

    while l <= r:
        mid = (l + r) // 2

        if a[mid] == x:
            return mid
        if a[mid] < x:
            l = mid + 1
        else:
            r = mid - 1

    return -1


n, x = map(int, input().split())
a = list(map(int, input().split()))

print(binary_search_pos(a, x))
Mẹo an toàn trong C++: nên viết mid = l + (r - l) / 2 thay vì (l + r) / 2. Với dữ liệu rất lớn, cách này tránh nguy cơ tràn số.

4. Các dạng bài dễ nhầm

Dạng bài Cách xử lý đúng Lỗi học sinh hay mắc
Tìm xem x có xuất hiện không Linear Search hoặc Binary Search nếu mảng đã sort Không dừng vòng lặp hoặc in sai vị trí
Đếm số lần xuất hiện của x Duyệt toàn mảng hoặc dùng lower_bound/upper_bound nếu đã sort Dùng binary search thường chỉ tìm được 1 vị trí, không đếm đủ
Tìm vị trí đầu tiên / cuối cùng của x Dùng biến lưu đáp án rồi tiếp tục thu hẹp trái/phải Thấy a[mid] == x là trả về ngay, nên không chắc là đầu/cuối
Tìm số nhỏ nhất lớn hơn hoặc bằng x Dùng lower_bound Nhầm với upper_bound
Tìm số đầu tiên lớn hơn x Dùng upper_bound Nhầm với lower_bound
#include 
using namespace std;

int main() {
    int n, x;
    cin >> n >> x;

    vector a(n);
    for (int i = 0; i < n; i++) cin >> a[i];

    int cnt = 0;
    for (int value : a) {
        if (value == x) cnt++;
    }

    cout << cnt;
    return 0;
}
n, x = map(int, input().split())
a = list(map(int, input().split()))

cnt = 0
for value in a:
    if value == x:
        cnt += 1

print(cnt)
#include 
using namespace std;

int main() {
    int n, x;
    cin >> n >> x;

    vector a(n);
    for (int i = 0; i < n; i++) cin >> a[i];

    sort(a.begin(), a.end());

    auto it1 = lower_bound(a.begin(), a.end(), x); // phần tử đầu tiên >= x
    auto it2 = upper_bound(a.begin(), a.end(), x); // phần tử đầu tiên > x

    int count_x = it2 - it1;
    cout << count_x;

    return 0;
}
from bisect import bisect_left, bisect_right

n, x = map(int, input().split())
a = list(map(int, input().split()))

a.sort()

left = bisect_left(a, x)    # vị trí đầu tiên có giá trị >= x
right = bisect_right(a, x)  # vị trí đầu tiên có giá trị > x

print(right - left)

5. Thực hành tương tác

Nhập một mảng và giá trị cần tìm. Hệ thống sẽ phân tích: mảng đã sắp xếp chưa, tìm thấy ở đâu, xuất hiện bao nhiêu lần, có thể dùng Binary Search không.

Bấm “Phân tích” để xem kết quả.

6. Lỗi thường gặp và cách tránh

Lỗi 1: Dùng Binary Search khi mảng chưa sắp xếp
Cách sửa: kiểm tra đề bài có nói “mảng tăng dần”, “đã sắp xếp” không. Nếu không có, phải sort hoặc dùng Linear Search tùy yêu cầu.
Lỗi 2: Sai điều kiện vòng lặp
Cách sửa: với mẫu cơ bản dùng while (l <= r). Khi cập nhật phải là l = mid + 1 hoặc r = mid - 1.
Lỗi 3: Nhầm chỉ số 0-based và 1-based
C++/Python dùng chỉ số từ 0. Nhưng đề thi đôi khi yêu cầu “vị trí thứ mấy”, khi đó thường cần in i + 1.
Lỗi 4: Tìm thấy một vị trí rồi tưởng là vị trí đầu tiên
Binary Search thường chỉ trả về một vị trí bất kỳ có x. Nếu cần vị trí đầu/cuối, phải viết biến ans hoặc dùng lower_bound.

7. Bài tập luyện tập phân loại

Các bài tập được chia theo mức độ để học sinh không nhầm dạng.

Mức 1 - Cơ bản

  1. Nhập mảng gồm n phần tử và giá trị x. In YES nếu x xuất hiện, ngược lại in NO.
  2. In vị trí đầu tiên của x trong mảng. Nếu không có, in -1.
  3. Đếm số lần xuất hiện của x trong mảng.

Mức 2 - Trung bình

  1. Mảng tăng dần. Dùng Binary Search để tìm vị trí của x.
  2. Mảng tăng dần có phần tử trùng nhau. Tìm vị trí đầu tiên của x.
  3. Mảng tăng dần có phần tử trùng nhau. Tìm vị trí cuối cùng của x.

Mức 3 - Khá

  1. Cho mảng chưa sắp xếp. Hãy đếm số lần xuất hiện của x sau khi sắp xếp bằng lower_boundupper_bound.
  2. Cho mảng tăng dần. Tìm số nhỏ nhất lớn hơn hoặc bằng x.
  3. Cho mảng tăng dần. Tìm số đầu tiên lớn hơn x.

Mức 4 - Nâng cao

  1. Cho q truy vấn, mỗi truy vấn hỏi x có trong mảng không. Mảng ban đầu có thể được sắp xếp trước.
  2. Đếm số cặp (i, j) sao cho a[i] + a[j] = x.
  3. Ứng dụng Binary Search trên đáp án: tìm giá trị nhỏ nhất thỏa mãn điều kiện.
💡 Gợi ý bài “tìm vị trí đầu tiên của x” bằng Binary Search
int first_pos(const vector& a, int x) {
    int l = 0, r = (int)a.size() - 1;
    int ans = -1;

    while (l <= r) {
        int mid = l + (r - l) / 2;

        if (a[mid] >= x) {
            if (a[mid] == x) ans = mid;
            r = mid - 1; // tiếp tục tìm bên trái
        } else {
            l = mid + 1;
        }
    }

    return ans;
}

8. Quiz kiểm tra nhanh

Câu 1. Binary Search dùng được trong trường hợp nào?

Câu 2. Độ phức tạp của Linear Search là gì?

Câu 3. Trong C++, hàm nào tìm phần tử đầu tiên lớn hơn hoặc bằng x trong vector đã sort?

Chọn đáp án để xem phản hồi.

Tổng kết

Linear Search đơn giản và dùng được với mọi mảng. Binary Search nhanh hơn rất nhiều, nhưng chỉ đúng khi dữ liệu đã sắp xếp. Khi bài có nhiều truy vấn tìm kiếm, hãy nghĩ đến việc sắp xếp trước và dùng binary_search, lower_bound, upper_bound.

➡ Tiếp theo: Sắp xếp và ứng dụng tìm kiếm trong các bài toán thực tế.