Thuật toán C/C++

Tìm kiếm nhị phân trong C, C++

Trong bài học này, bạn sẽ tìm kiếm trên mảng đã sắp xếp với thời gian O(log n) bằng vòng lặp tự viết trong C và std::lower_bound trong C++.

Giới thiệu

Tìm kiếm nhị phân so sánh giá trị cần tìm với phần tử ở giữa phạm vi tìm kiếm, rồi loại bỏ một nửa không thể chứa giá trị đó. Lặp lại quá trình này, phạm vi tìm kiếm thu hẹp rất nhanh, nhưng dữ liệu đầu vào bắt buộc phải được sắp xếp trước.

Những điểm quan trọng

  • Kiểm thử với dữ liệu rỗng, chỉ có một phần tử, có giá trị trùng và đã được sắp xếp.
  • Viết cho đúng trước, tối ưu sau.
  • Trong code thực tế, ưu tiên dùng các hàm có sẵn của thư viện chuẩn.

Mô phỏng Tìm kiếm nhị phân trong C, C++

O(log n)

Nhấn Phát hoặc Từng bước để theo dõi từng phép so sánh và thay đổi dữ liệu.

Code ví dụ bằng C và C++

C
Chạy code →
main.c
#include <stdio.h>

int search(const int *values, int size, int target) {
    int low = 0;
    int high = size - 1;
    while (low <= high) {
        int middle = low + (high - low) / 2;
        if (values[middle] == target) return middle;
        if (values[middle] < target) low = middle + 1;
        else high = middle - 1;
    }
    return -1;
}

int main(void) {
    int values[] = {3, 7, 11, 16, 23, 28};
    printf("index=%d\n", search(values, 6, 23));
}
Kết quả khi chạy
index=4
C++
Chạy code →
main.cpp
#include <algorithm>
#include <iostream>
#include <vector>

int main() {
    std::vector values{3, 7, 11, 16, 23, 28};
    auto match = std::lower_bound(values.begin(), values.end(), 23);
    std::cout << "index="
              << std::distance(values.begin(), match) << '\n';
}
Kết quả khi chạy
index=4

So sánh C và C++

Trong phiên bản C, vị trí giữa được tính bằng low + (high - low) / 2 thay vì (low + high) / 2 để tránh tràn số khi chỉ số rất lớn. Mỗi lần so sánh, low hoặc high được dịch đến nửa còn lại. Phiên bản C++ dùng std::lower_bound để tìm vị trí đầu tiên không nhỏ hơn giá trị cần tìm. Cả hai đều có độ phức tạp O(log n).

C

Vòng lặp, con trỏ, độ dài và vùng nhớ tạm đều được viết tường minh.

C++

Iterator và các thuật toán chuẩn tách thao tác xử lý khỏi cách dữ liệu được lưu trữ.

Bài tập mở rộng

Hãy chạy cả hai phiên bản, sau đó thử thay đổi code để quan sát sự khác biệt về mức độ an toàn mà mỗi ngôn ngữ mang lại.

  • Tự mô phỏng từng phép so sánh trên giấy.
  • Thử với giá trị trùng lặp và các giá trị cực lớn, cực nhỏ.
  • Đo thời gian chạy của code tự viết và so sánh với thư viện chuẩn.

Luyện tập với thử thách

Áp dụng kiến thức của bài học này để giải một bài toán thực tế. Mỗi thử thách chạy ngay trên trình duyệt, có kiểm thử tức thì và AI nhận xét.

Tất cả thử thách