stanford-oval/wikipedia huggingface dataset:
Tìm kiếm nhị phân

Bài này viết về tìm kiếm trên một mảng hữu hạn đã được sắp xếp. Đối với tìm kiếm các giá trị của một hàm liên tục, xem phương pháp chia đôi.
Thuật toán tìm kiếm tìm vị trí của một giá trị cần tìm trong một mảng đã được sắp xếpBản mẫu:SHORTDESC:Thuật toán tìm kiếm tìm vị trí của một giá trị cần tìm trong một mảng đã được sắp xếp
| --- | --- |
Minh họa thuật toán tìm kiếm nhị phân, trong đó 7 là giá trị cần tìm
Phân loại: Thuật toán tìm kiếm
Cấu trúc dữ liệu: Mảng
Hiệu suất trường hợp tệ nhất: O(log n)
Hiệu suất trường hợp tốt nhất: O(1)
Hiệu suất trung bình: O(log n)
Độ phức tạp không gian trường hợp tệ nhất: O(1)
Tối ưu: Có
Trong khoa học máy tính, tìm kiếm nhị phân (tiếng Anh: binary search), còn gọi là tìm kiếm nửa khoảng (half-interval search), tìm kiếm logarit (logarithmic search), hay chặt nhị phân (binary chop), là một thuật toán tìm kiếm xác định vị trí của một giá trị cần tìm trong một mảng đã được sắp xếp. Thuật toán tiến hành so sánh giá trị cần tìm với phần tử đứng giữa mảng. Nếu hai giá trị không bằng nhau, phần nửa mảng không chứa giá trị cần tìm sẽ bị bỏ qua và tiếp tục tìm kiếm trên nửa còn lại, một lần nữa lấy phần tử ở giữa và so sánh với giá trị cần tìm, cứ thế lặp lại cho đến khi tìm thấy giá trị đó. Nếu phép tìm kiếm kết thúc khi nửa còn lại trống thì giá trị cần tìm không có trong mảng.
Tìm kiếm nhị phân chạy theo thời gian logarit trong trường hợp tệ nhất, thực hiện  O(\log n) bước so sánh, trong đó  n là số phần tử trong mảng,  O là kí hiệu O lớn, và  \log  là phép toán logarit. Thuật toán tìm kiếm nhị phân nhanh hơn so với tìm kiếm tuyến tính, ngoại trừ các trường hợp mảng có kích thước nhỏ. Tuy nhiên, mảng phải được sắp xếp trước khi áp dụng tìm kiếm nhị phân. Một số cấu trúc dữ liệu chuyên dụng được thiết kế cho việc tìm kiếm nhanh, ví dụ như bảng băm, có thể thực hiện tìm hiệu quả hơn tìm kiếm nhị phân. Tuy nhiên, thuật toán này có thể dùng để giải quyết nhiều loại vấn đề hơn, như tìm phần tử nhỏ nhất hoặc lớn nhất tiếp theo trong mảng so với giá trị cho trước, kể cả khi nó không có trong mảng.
Có nhiều biến thể của phép tìm kiếm nhị phân. Cụ thể, phương pháp "đổ xuống một phần" (fractional cascading) giúp tăng tốc tìm kiếm nhị phân với cùng một giá trị trong nhiều mảng. Phương pháp này cho phép giải quyết hiệu quả một số vấn đề về tìm kiếm trong hình học tính toán và nhiều lĩnh vực khác. Thuật toán tìm kiếm mũ (exponential search) mở rộng tìm kiếm nhị phân sang các danh sách không có giới hạn. Các cấu trúc dữ liệu cây tìm kiếm nhị phân và B-cây được xây dựng dựa trên tìm kiếm nhị phân.
Thuật toán

Thuật toán tìm kiếm nhị phân hoạt động trên các mảng đã được sắp xếp. Thuật toán bắt đầu bằng việc so sánh một phần tử đứng chính giữa mảng với giá trị cần tìm. Nếu bằng nhau, vị trí của nó trong mảng sẽ được trả về. Nếu giá trị cần tìm nhỏ hơn phần tử này, quá trình tìm kiếm tiếp tục ở nửa nhỏ hơn của mảng. Nếu giá trị cần tìm lớn hơn phần tử ở giữa, quá trình tìm kiếm tiếp tục ở nửa lớn hơn của mảng. Bằng cách này, ở mỗi phép lặp thuật toán có thể loại bỏ nửa mảng mà giá trị cần tìm chắc chắn không xuất hiện.
Thuật toán > Quy trình

Cho một mảng  A có  n phần tử với các giá trị hoặc bản ghi  A_{0},A_{1},A_{2},\ldots ,A_{n-1}đã được sắp xếp sao cho  A_{0}\leq A_{1}\leq A_{2}\leq \cdots \leq A_{n-1}, và giá trị cần tìm  T, chương trình con sau đây sử dụng tìm kiếm nhị phân để tìm chỉ số của  T trong  A.
Gán  L với giá trị  0 và  R với giá trị  n-1.
Nếu  L>R, quá trình tìm kiếm thất bại.
Gán  m (vị trí của phần tử đứng giữa) với giá trị floor của  {\frac {L+R}{2}}, tức là số nguyên lớn nhất nhỏ hơn hoặc bằng  {\frac {L+R}{2}}.
Nếu  A_{m}<T, gán  L với  m+1 và quay lại bước 2.
Nếu  A_{m}>T, gán  R với  m-1 và quay lại bước 2.
Khi  A_{m}=T, quá trình tìm kiếm hoàn tất; trả về  m.
Quy trình lặp này dùng hai biến  L và  R để lưu giới hạn tìm kiếm. Quy trình này có thể diễn giải bằng mã giả như dưới đây, trong đó tên các biến và kiểu giữ nguyên so với như trên, floor là hàm floor, và không_thành_công là một giá trị cụ thể thông báo tìm kiếm thất bại.
function binary_search(A, n, T) is
    L:= 0
    R:= n − 1
    while L ≤ R do
        m:= floor((L + R) / 2)
        if A[m] < T then
            L:= m + 1
        else if A[m] > T then
            R:= m - 1
        else:
            return m
    return không_thành_công
Ngoài ra, thuật toán có thể lấy giá trị ceiling của  {\frac {L+R}{2}}. Điều này có thể thay đổi kết quả nếu giá trị cần tìm xuất hiện nhiều hơn một lần trong mảng.
Thuật toán > Quy trình > Cách làm khác

Trong quy trình trên, thuật toán kiểm tra phần tử ở giữa ( m) có bằng giá trị cần tìm ( T) không ở mỗi phép lặp. Một số cách làm bỏ qua bước này ở mỗi phép lặp. Khi đó thuật toán chỉ kiểm tra điều này khi chỉ còn một phần tử còn lại (khi  L=R). Nhờ đó mà vòng lặp so sánh được thực hiện nhanh hơn do mỗi phép lặp đã loại bỏ được một bước so sánh. Tuy nhiên, với cách làm này thì số phép lặp trung bình tăng lên.
Hermann Bottenbruch cho xuất bản cách áp dụng đầu tiên bỏ qua bước kiểm tra này vào năm 1962.
Gán  L với giá trị  0 và  R với giá trị  n-1.
Khi L\neq R ,
Gán  m (vị trí của phần tử đứng giữa) với giá trị ceiling của  {\frac {L+R}{2}}, tức là số nguyên nhỏ nhất lớn hơn hoặc bằng  {\frac {L+R}{2}}.
Nếu  A_{m}>T, gán  R với  m-1.
Trường hợp còn lại,  A_{m}\leq T; gán  L với  m.
Khi  L=R, quá trình tìm kiếm hoàn tất. Nếu  A_{L}=T, trả về  L. Nếu không, tìm kiếm thất bại.
Với ceil là hàm ceiling, mã giả cho phiên bản này như sau:
function binary_search_alternative(A, n, T) is
    L:= 0
    R:= n − 1
    while L != R do
        m:= ceil((L + R) / 2)
        if A[m] > T then
            R:= m - 1
        else:
            L:= m
    if A[L] = T then
        return L
    return không_thành_công
Thuật toán > Phần tử lặp lại

Quy trình trên có thể trả về bất cứ chỉ số nào có giá trị phần tử bằng giá trị cần tìm, kể cả khi trong mảng có các phần tử xuất hiện lặp lại. Ví dụ, với mảng  [1,2,3,4,4,5,6,7] và giá trị cần tìm là  4, thuật toán có thể trả về một trong hai kết quả đúng là phần tử thứ 4 (chỉ số là 3) hoặc thứ 5 (chỉ số là 4). Quy trình chuẩn trong trường hợp này sẽ trả về phần tử thứ 4 (chỉ số 3). Thuật toán này không phải lúc nào cũng trả về vị trí đầu tiên xuất hiện giá trị cần tìm (ví dụ với mảng  [1,2,4,4,4,5,6,7], kết quả trả về vẫn là phần tử thứ 4). Tuy nhiên, có một số trường hợp cần phải tìm phần tử nằm xa nhất về phía bên trái hoặc bên phải mang giá trị cần tìm khi giá trị này xuất hiện lặp lại trong mảng. Trong ví dụ trên, phần tử thứ 4 là phần tử đứng xa nhất về bên trái mang giá trị 4, trong khi phần tử thứ 5 là phần từ đứng xa nhất về bên phải mang giá trị 4. Cách làm thứ hai ở trên sẽ luôn trả về chỉ số của phần tử đứng xa nhất về bên phải nếu tồn tại các phần tử lặp lại.
Thuật toán > Phần tử lặp lại > Quy trình tìm phần tử xa nhất về bên trái

Để tìm phần tử xa nhất về bên trái, ta có thể dùng quy trình sau:
Gán  L với giá trị  0 và  R với  n.
Khi  L<R,
Gán m (vị trí của phần tử đứng giữa) với giá trị floor của {\frac {L+R}{2}} , tức là số nguyên lớn nhất nhỏ hơn hoặc bằng {\frac {L+R}{2}} .
Nếu  A_{m}<T, gán  L với  m+1.
Trường hợp còn lại,  A_{m}\geq T; gán  R với  m.
Trả về  L.
Nếu  L<n và  A_{L}=T thì  A_{L} là phần tử đứng xa nhất về bên trái có giá trị bằng  T. Kể cả khi  T không nằm trong mảng,  L là hạng của  T trong mảng, hay số phần tử trong mảng nhỏ hơn  T.
Với floor là hàm floor, mã giả cho phiên bản này như sau:
function binary_search_leftmost(A, n, T):
    L:= 0
    R:= n
    while L < R:
        m:= floor((L + R) / 2)
        if A[m] < T:
            L:= m + 1
        else:
            R:= m
    return L
Thuật toán > Phần tử lặp lại > Quy trình tìm phần tử xa nhất về bên phải

Để tìm phần tử xa nhất về bên phải, ta có thể dùng quy trình sau:
Gán  L với giá trị  0 và  R với  n.
Khi  L<R,
Gán m (vị trí của phần tử đứng giữa) với giá trị floor của {\frac {L+R}{2}} , tức là số nguyên lớn nhất nhỏ hơn hoặc bằng {\frac {L+R}{2}} .
Nếu  A_{m}>T, gán  R với  m.
Trường hợp còn lại,  A_{m}\leq T; gán  L với  m+1.
Trả về  R-1.
Nếu  L>0 và  A_{L-1}=T, thì  A_{L-1} là phần tử đứng xa nhất về phía bên phải có giá trị bằng  T. Kể cả khi  T không có trong mảng,  n-L sẽ là số phần tử trong mảng lớn hơn  T.
Với floor là hàm floor, mã giả cho phiên bản này như sau:
function binary_search_rightmost(A, n, T):
    L:= 0
    R:= n
    while L < R:
        m:= floor((L + R) / 2)
        if A[m] > T:
            R:= m
        else:
            L:= m + 1
    return R - 1
Hiệu suất > Độ phức tạp không gian

Thuật toán tìm kiếm nhị phân cần ba con trỏ để trỏ tới các phần tử, bất kể kích thước của mảng; đó có thể là chỉ số các phần tử trong mảng hoặc con trỏ tới địa chỉ trong bộ nhớ. Tuy nhiên, thuật toán cần ít nhất  \left\lceil \log _{2}(n)\right\rceil  bit để mã hóa một con trỏ tới một phần tử trong mảng có  n phần tử. Do đó, độ phức tạp không gian của tìm kiếm nhị phân là  O(\log n). Ngoài ra, thuật toán còn cần  O(n) không gian để lưu trữ mảng.
Hiệu suất > Trường hợp trung bình

Số phép lặp trung bình được thực hiện bởi thuật toán tùy thuộc vào xác suất mỗi phần tử được thực hiện tìm kiếm. Trường hợp trung bình khi tìm kiếm thành công và không thành công là khác nhau. Ta giả sử mỗi phần tử có xác suất được tìm như nhau nếu tìm kiếm thành công. Nếu tìm kiếm không thành công, ta giả sử các khoảng giữa và ngoài các phần tử có xác suất được tìm giống nhau. Trường hợp trung bình khi tìm kiếm thành công là số phép lặp cần thực hiện để tìm mọi phần tử chính xác một lần, chia cho  n, số phần tử trong mảng. Trường hợp trung bình khi tìm kiếm không thành công là số phép lặp cần thực hiện để tìm một phần tử trong mọi khoảng chính xác một lần, chia cho  n+1 khoảng.
Hiệu suất > Trường hợp trung bình > Tìm kiếm thành công

Khi biểu diễn bằng cây nhị phân, một lần tìm kiếm thành công có thể được biểu diễn bằng một đường đi từ gốc tới nút cần tìm, gọi là đường đi trong (internal path). Độ dài của một đường đi là số cạnh (đường nối giữa các nút) mà đường đó đi qua. Số phép lặp mà một lần tìm kiếm thực hiện, với điều kiện độ dài của đường đi tương ứng với lần tìm đó là  l, là  l+1 tính cả phép lặp ban đầu. Độ dài đường đi trong (internal path length) là tổng độ dài tất cả các đường đi trong. Do chỉ có một đường đi duy nhất từ gốc tới bất cứ nút nào, mỗi đường trong đó biểu diễn cho một phép tìm kiếm phần tử tương ứng. Nếu có  n phần tử, và độ dài đường trong là  I(n), thì số phép lặp trung bình cho một lần tìm kiếm thành công là  T(n)=1+{\frac {I(n)}{n}}, trong đó đã cộng thêm một bước lặp ở đầu.
Do tìm kiếm nhị phân là thuật toán tối ưu cho việc tìm kiếm bằng cách so sánh, bài toán được đơn giản hóa thành việc tính độ dài đường đi trong tối thiểu của tất cả cây nhị phân có  n nút, tức là bằng:
I(n)=\sum _{k=1}^{n}\left\lfloor \log _{2}(k)\right\rfloor
Ví dụ, với một mảng 7 phần tử, phần tử gốc cần một phép lặp, hai phần tử bên dưới gốc cần hai phép lặp, và bốn phần tử dưới nữa gần ba phép lặp. Trong trường hợp này, độ dài đường đi trong là:
\sum _{k=1}^{7}\left\lfloor \log _{2}(k)\right\rfloor =0+2(1)+4(2)=2+8=10
Số phép lặp trung bình sẽ là  1+{\frac {10}{7}}=2{\frac {3}{7}} dựa theo công thức với trường hợp trung bình. Tổng  I(n) có thể rút gọn thành:
I(n)=\sum _{k=1}^{n}\left\lfloor \log _{2}(k)\right\rfloor =(n+1)\left\lfloor \log _{2}(n+1)\right\rfloor -2^{\left\lfloor \log _{2}(n+1)\right\rfloor +1}+2
Thay  I(n) vào phương trình  T(n):
T(n)=1+{\frac {(n+1)\left\lfloor \log _{2}(n+1)\right\rfloor -2^{\left\lfloor \log _{2}(n+1)\right\rfloor +1}+2}{n}}=\lfloor \log _{2}(n)\rfloor +1-(2^{\lfloor \log _{2}(n)\rfloor +1}-\lfloor \log _{2}(n)\rfloor -2)/n
Với  n là một số nguyên, phương trình trên tương đương với phương trình trong trường hợp trung bình cho một lần tìm kiếm thành công như đã chỉ ra ở trên.
Hiệu suất > Trường hợp trung bình > Tìm kiếm không thành công

Ta có thể biểu diễn lần tìm kiếm không thành công bằng cách thêm vào cây các nút ngoài, tạo thành cây nhị phân mở rộng. Nếu một nút trong, hoặc một nút có trong cây, có ít hơn hai nút con, thì ta sẽ thêm vào các nút con bổ sung, gọi là các nút ngoài, để mỗi nút trong đều có hai nút con. By doing so, an unsuccessful search can be represented as a path to an external node, whose parent is the single element that remains during the last iteration. Đường đi ngoài (external path) là đường đi từ gốc đến một nút ngoài. Độ dài đường đi ngoài (external path length) là tổng độ dài tất cả đường đi ngoài unique. Nếu số phần tử là  n ( n là số nguyên dương), và độ dài đường đi ngoài là  E(n), thì số phép lặp trung bình cho một lần tìm kiếm không thành công là  T'(n)={\frac {E(n)}{n+1}}, trong đó đã tính một phép lặp lúc đầu. Trong công thức này, ta lấy độ dài đường đi ngoài chia cho  n+1 chứ không phải  n vì có  n+1 đường đi ngoài biểu diễn cho các khoảng giữa và ngoài các phần tử trong mảng.
Tương tự, bài toán này có thể đơn giản hóa thành bài toán tính độ dài đường đi ngoài tối thiếu của tất cả cây nhị phân có  n nút. Với tất cả các cây nhị phân, độ dài đường đi ngoài bằng độ dài đường đi trong cộng với  2n. Thay  I(n) vào ta có:
E(n)=I(n)+2n=\left[(n+1)\left\lfloor \log _{2}(n+1)\right\rfloor -2^{\left\lfloor \log _{2}(n+1)\right\rfloor +1}+2\right]+2n=(n+1)(\lfloor \log _{2}(n)\rfloor +2)-2^{\lfloor \log _{2}(n)\rfloor +1}
Thay  E(n) vào công thức tính  T'(n), ta có thể xác định trường hợp trung bình cho những lần tìm kiếm không thành công:
T'(n)={\frac {(n+1)(\lfloor \log _{2}(n)\rfloor +2)-2^{\lfloor \log _{2}(n)\rfloor +1}}{(n+1)}}=\lfloor \log _{2}(n)\rfloor +2-2^{\lfloor \log _{2}(n)\rfloor +1}/(n+1)
Hiệu suất > Trường hợp trung bình > Hiệu suất của các cách thay thế

Mỗi phép lặp trong cách tìm kiếm nhị phân trên thực hiện một hoặc hai lần so sánh để kiểm tra phần tử ở giữa có bằng với giá trị cần tìm không. Giả sử mỗi phần tử có xác suất được tìm bằng nhau, mỗi phép lặp thực hiện trung bình 1,5 lần so sánh. Một cách làm khác của thuật toán sẽ thực hiện kiểm tra phần tử giữa ở cuối mỗi lần tìm kiếm. Theo cách này, trung bình mỗi phép lặp bỏ qua 0,5 lần so sánh, tiết kiệm thời gian hơn một chút trên mỗi phép lặp ở hầu hết các loại máy tính. Tuy nhiên, cách này lại khiến mỗi lần tìm kiếm luôn phải thực hiện số phép lặp tối đa, trung bình mỗi lần tìm cộng thêm một phép lặp. Vì vòng lặp so sánh chỉ được thực hiện 



⌊

log

2


⁡
(
n
)
+
1
⌋


{\textstyle \lfloor \log _{2}(n)+1\rfloor }

 lần trong trường hợp tệ nhất, việc tăng nhẹ hiệu suất ở mỗi phép lặp không thể bù lại cho phép lặp cần thực hiện thêm khi 



n


{\textstyle n}

 không lớn.
Hiệu suất > Thời gian chạy và mức sử dụng cache

Trong quá trình phân tích hiệu suất của thuật toán, một vấn đề khác cần lưu ý là thời gian cần để so sánh hai phần tử. Với các số nguyên và chuỗi ký tự, khoảng thời gian này tăng tuyến tính do độ dài mã hóa (thường là số bit) của các phần tử tăng theo. Ví dụ, một cặp số nguyên dương 64 bit sẽ cần phải so sánh số bit gấp đôi so với một cặp số nguyên dương 32 bit. Trường hợp tệ nhất được đạt đến khi hai số nguyên bằng nhau. Điều này có thể đáng lưu tâm khi độ dài mã hóa của các phần tử ở mức lớn, ví dụ như khi so sánh các số thuộc kiểu nguyên lớn hơn hay so sánh các chuỗi ký tự dài, khiến cho việc so sánh rất tốn thời gian. Hơn nữa, so với các số nguyên hoặc chuỗi ký tự ngắn thì so sánh các giá trị dấu phẩy động (cách biểu diễn số thông dụng nhất của số thực) thường còn tốn thời gian hơn..
Trên hầu hết các kiểu kiến trúc máy tính, bộ vi xử lý có bộ nhớ cache riêng tách biệt khỏi RAM. Do nằm ngay trong bộ xử lý, bộ nhớ cache có thể truy cập nhanh hơn nhưng thường chỉ chứa được ít dữ liệu hơn RAM. Do đó, hầu hết các bộ xử lý lưu địa chỉ những vùng bộ nhớ đã được truy cập gần đây và cả những vùng bộ nhớ xung quanh chúng. Ví dụ, khi truy cập vào một phần tử trong mảng, phần tử này, cùng với cả những phần tử được lưu gần đó, có thể được lưu vào trong RAM để sau đó có thể truy cập nhanh hơn được vào các phần tử khác liền kề (tính địa phương trong truy xuất - locality of reference). Với một mảng đã sắp xếp, quá trình tìm kiếm nhị phân có thể phải nhảy sang các vùng bộ nhớ nằm xa nếu mảng có kích thước lớn, không giống như các thuật toán (như tìm kiếm tuyến tính hay dò tuyến tính trong bảng băm) truy cập các phần tử theo thứ tự lần lượt. Điều này làm thời gian chạy của thuật toán tăng lên đôi chút với các mảng lớn trên hầu hết các hệ thống.
Tìm kiếm nhị phân với các hệ thống khác

Áp dụng tìm kiếm nhị phân với các mảng đã được sắp xếp là một giải pháp rất không hiệu quả khi xen giữa các phép chèn và xóa còn là các phép truy hồi, mỗi thao tác đó phải mất 



O
(
n
)


{\textstyle O(n)}

 thời gian để thực hiện. Ngoài ra, yêu cầu phải sắp xếp trước các mảng có thể làm phức tạp việc sử dụng bộ nhớ, đặc biệt là khi các phần tử thường được chèn vào trong mảng. Một số cấu trúc dữ liệu khác có thể hỗ trợ các thao tác chèn và xóa hiệu quả hơn nhiều. Tìm kiếm nhị phân có thể được dùng để thực hiện so khớp chính xác và thao tác quan hệ tập hợp (xác định giá trị cần tìm có phải là một tập hợp nhiều giá trị không). Hai bài toán này cũng có thể được thực hiện nhanh hơn trên các cấu trúc dữ liệu khác. Tuy nhiên, khác với các hệ thống tìm kiếm khác, tìm kiếm nhị phân hiệu quả hơn trong phép so khớp xấp xỉ, thường chỉ thực hiện trong 



O
(
log
⁡
n
)


{\textstyle O(\log n)}

 thời gian bất kể kiểu hay cấu trúc của các giá trị. Ngoài ra còn có một số phép toán, như tìm phần tử nhỏ nhất và lớn nhất, có thể được thực hiện hiệu quả trên mảng đã được sắp xếp.
Tìm kiếm nhị phân với các hệ thống khác > Tìm kiếm tuyến tính

Tìm kiếm tuyến tính là một thuật toán tìm kiếm đơn giản: nó kiểm tra mọi bản ghi cho tới khi tìm thấy giá trị cần tìm. Tìm kiếm tuyến tính có thể được thực hiện trên danh sách liên kết, cho phép các thao tác chèn và xóa nhanh hơn so với mảng. Tìm kiếm nhị phân nhanh hơn tìm kiếm tuyến tính trên các mảng đã được sắp xếp trừ khi mảng có kích thước nhỏ, mặc dù trước khi tìm kiếm cần phải thực hiện sắp xếp lại mảng trước. Tất cả các thuật toán sắp xếp dựa trên thao tác so sánh các phần tử, như sắp xếp nhanh và sắp xếp trộn, cần ít nhất 



O
(
n
log
⁡
n
)


{\textstyle O(n\log n)}

 phép so sánh trong trường hợp tệ nhất. Khác với tìm kiếm tuyến tính, tìm kiếm nhị phân có thể được ứng dụng để tìm so khớp xấp xỉ một cách hiệu quả. Một số thao tác như tìm phần tử nhỏ nhất và lớn nhất có thể được thực hiện hiệu quả chỉ khi mảng đã được sắp xếp.
Tìm kiếm nhị phân với các hệ thống khác > Cây

Cây tìm kiếm nhị phân là một cấu trúc dữ liệu dạng cây nhị phân hoạt động dựa trên nguyên lý của tìm kiếm nhị phân. Các bản ghi trong cây được biểu diễn theo thứ tự đã được sắp xếp, và mỗi bản ghi có thể được tìm bằng một thuật toán tương tự tìm kiếm nhị phân, thực hiện trung bình theo thời gian logarit. Các phép chèn và xóa cũng cần trung bình thời gian logarit trong cây tìm kiếm nhị phân. Chúng có thể được thực hiện nhanh hơn so với các thao tác chèn và xóa theo thời gian tuyến tính trên các mảng đã được sắp xếp, đồng thời các thao tác có thể thực hiện trên mảng đã được sắp xếp cũng có thể được thực hiện trên cây nhị phân, bao gồm cả các phép truy vấn khoảng và truy vấn xấp xỉ.
Tuy nhiên, tìm kiếm nhị phân thường hiệu quả hơn trong việc tìm kiếm, do các cây nhị phân hầu như đều không cân bằng tuyệt đối, khiến hiệu suất kém hơn đôi chút so với tìm kiếm nhị phân. Điều này thậm chí vẫn áp dụng với các cây tìm kiếm nhị phân tự cân bằng, vì chúng hiếm khi tạo ra cây có số bậc nhỏ nhất có thể. Ngoại trừ các cây tìm kiếm nhị phân đã cân bằng, việc có quá ít số nút trong có đúng hai nút con có thể khiến cây bị mất cân bằng rất nhiều, khiến thời gian tìm kiếm ở trường hợp trung bình và tệ nhất có thể tiến tới ngưỡng 



n


{\textstyle n}

 phép so sánh. Cây tìm kiếm nhị phân cần nhiều không gian hơn so với mảng đã được sắp xếp.
Cây tìm kiếm nhị phân hữu ích nhất cho việc tìm kiềm nhanh trong các ổ cứng ngoài, bởi cây tìm kiếm nhị phân có thể được dựng hiệu quả trong các hệ thống tập tin. Cấu trúc B-cây tổng quát hóa phương pháp tổ chức cây này. B-cây thường được dùng để tổ chức các ổ lưu trữ dài hạn như cơ sở dữ liệu và hệ thống tập tin.
Tìm kiếm nhị phân với các hệ thống khác > Băm

Với các mảng kết hợp, bảng băm, một cấu trúc dữ liệu dùng hàm băm để ánh xạ các khóa thành các bản ghi, thường hoạt động nhanh hơn tìm kiếm nhị phân trên một mảng chứa các bản ghi đã được sắp xếp. Hầu hết các cách triển khai bảng băm chỉ yêu cầu trung bình thời gian hằng số khấu hao. Tuy nhiên, việc băm có thể không hữu ích khi thực hiện các bài toán so khớp xấp xỉ, ví dụ như tính khóa nhỏ nhất tiếp theo, khóa lớn nhất tiếp theo và khóa gần nhất, do khi tìm kiếm thất bại, thông tin duy nhất được đưa ra là giá trị cần tìm không có trong bất cứ bản ghi nào. Tìm kiếm nhị phân là cách làm lý tưởng đối với những bài toán như vậy, khi chỉ thực hiện với thời gian chạy logarit. Tìm kiếm nhị phân cũng hỗ trợ so khớp xấp xỉ. Một số phép toán, như tìm phần tử nhỏ nhất và lớn nhất, có thể được thực hiện hiệu quả trên các mảng đã được sắp xếp, nhưng không thể trên bảng băm.
Tìm kiếm nhị phân với các hệ thống khác > Các thuật toán quan hệ tập hợp

Một vấn đề liên quan tới tìm kiếm là quan hệ tập hợp. Bất cứ thuật toán nào thực hiện tra cứu, như tìm kiếm nhị phân, cũng có thể dùng cho quan hệ tập hợp. Một số thuật toán khác được thiết kế phù hợp hơn với quan hệ tập hợp. Mảng bit là cách làm đơn giản nhất, thường được dùng khi số khóa bị giới hạn. Cấu trúc này lưu trữ các bit một cách nhỏ gọn, mỗi bit biểu diễn cho một khóa trong khoảng cho trước. Mảng bit hoạt động rất nhanh, chỉ trong thời gian 



O
(
1
)


{\textstyle O(1)}

.  Một loại mảng Judy là Judy1 có thể xử lý hiệu quả các khóa 64-bit.
Nếu chỉ cần kết quả xấp xỉ, ta có thể sử dụng bộ lọc Bloom, một cấu trúc dữ liệu xác suất khác dựa trên hàm băm, lưu trữ một tập hợp các khóa bằng cách sử dụng một mảng bit và nhiều hàm băm để mã hóa các khóa. Các bộ lọc Bloom chiếm ít không gian hơn nhiều so với các mảng bit trong hầu hết mọi trường hợp và không hoạt động chậm hơn là bao: với 



k


{\textstyle k}

 hàm băm, các phép truy vấn kiểm tra phần tử chỉ cần thời gian 



O
(
k
)


{\textstyle O(k)}

. Tuy nhiên, sử dụng bộ lọc Bloom có thể đem kết quả dương tính giả.
Tìm kiếm nhị phân với các hệ thống khác > Các cấu trúc dữ liệu khác

Còn có các cấu trúc dữ liệu khác có thể cải thiện tìm kiếm nhị phân trong một số trường hợp với cả mục đích tìm kiếm lẫn các thao tác khác có thể được thực hiện trên các mảng đã được sắp xếp. Ví dụ, các phép tìm kiếm, so khớp xấp xỉ và các thao tác khác trên mảng đã được sắp xếp có thể được thực hiện hiệu quả hơn tìm kiếm nhị phân nếu áp dụng trên các cấu trúc dữ liệu chuyên biệt như cây van Emde Boas, fusion trees, trie và mảng bit. Các cấu trúc dữ liệu chuyên biệt này thường chỉ nhanh hơn vì chúng sử dụng các tính chất của những khóa có điều kiện nhất định (thông thường những khóa này là các số nguyên nhỏ), và do đó thời gian chạy hoặc không gian cần sử dụng có thể lớn nếu không đáp ứng được các điều kiện ấy. Với điều kiện có thể sắp xếp được các khóa, các thao tác này luôn luôn có thể được thực hiện hiệu quả trên một mảng đã được sắp xếp trước, không phụ thuộc vào các khóa. Một số cấu trúc như mảng Judy sử dụng kết hợp nhiều phương pháp nhằm đơn giản hóa điều kiện trên, nhưng vẫn giữ được sự hiệu quả và khả năng thực hiện so khớp xấp xỉ.