2012-12-17 48 views
5

Tôi tình cờ đang xây dựng tìm kiếm nhị phân trong Python, nhưng câu hỏi có nhiều hơn để làm với cấu trúc tìm kiếm nhị phân nói chung. Giả sử tôi có khoảng một ngàn ứng cử viên đủ điều kiện tôi đang tìm kiếm thông qua tìm kiếm nhị phân, thực hiện cách tiếp cận cổ điển để chia nhỏ tập dữ liệu được sắp xếp và lặp lại quy trình này để thu hẹp tập hợp đủ điều kiện để lặp lại. Các thí sinh chỉ là chuỗi tên, (định dạng đầu cuối, ví dụ: "Peter Jackson") Tôi ban đầu sắp xếp các thiết lập thứ tự abc và sau đó tiến hành chia làm hai đoạn sử dụng một cái gì đó như thế này:Tìm kiếm chuỗi nhị phân - chiều rộng thùng tối thiểu?

hi = len(names) 
lo = 0 
while lo < hi: 
    mid = (lo+hi)//2 
    midval = names[mid].lower() 
    if midval < query.lower(): 
    lo = mid+1 
    elif midval > query.lower(): 
    hi=mid 
    else: 
    return midval 
return None 

Mã này chuyển thể từ đây: https://stackoverflow.com/a/212413/215608

Đây là điều, quy trình trên giả định một kết quả khớp chính xác hoặc không có kết quả nào cả. Điều gì sẽ xảy ra nếu truy vấn chỉ đơn thuần là một "Peter", nhưng có một số peters có tên họ khác nhau? Để trả lại tất cả các Peters, người ta sẽ phải đảm bảo rằng "bins" chia đôi không bao giờ có quá nhỏ như ngoại trừ kết quả đủ điều kiện. Quá trình bisection sẽ phải chấm dứt và nhượng lại một cái gì đó giống như một regex/thường xuyên chuỗi trận đấu cũ để trả lại tất cả các Peters.

Tôi không yêu cầu cách thực hiện điều này là loại tìm kiếm này được gọi là ... tìm kiếm nhị phân với tiêu chí phân tách cho "kích thước bin" được gọi là gì? Một cái gì đó có điều kiện chia nhỏ tập dữ liệu và khi tiêu chí được hoàn thành, hãy quay lại một số dạng kết hợp chuỗi khác để đảm bảo rằng có thể có ký tự kết thúc có hiệu quả trên truy vấn (do đó tìm kiếm "Peter" sẽ nhận được " Peter Jacksons "và" Peter Edwards ")

Hy vọng rằng tôi đã rõ ràng ý tôi là gì. Tôi nhận ra trong kịch bản DB điển hình các tên có thể được tách ra, đây chỉ là dự định như là một bằng chứng về khái niệm.

+0

trong trường hợp xấu nhất có thể là tất cả các peters, phải không? – kdubs

+0

Thật vậy, trong kịch bản tồi tệ nhất (hoặc tôi nên nói một dự định?) Tất cả các Peters sẽ được lấy. – DeaconDesperado

+0

vì vậy có vẻ như bạn muốn bạn phải bin theo những gì bạn có thể tìm kiếm theo. Tôi đoán bạn có thể làm một nhị phân cho đến khi bạn tìm thấy một trận đấu, và sau đó thực hiện tìm kiếm tuyến tính theo cả hai hướng để tìm tất cả các trận đấu khác. không chắc chắn nếu tôi muốn gọi nó là thùng, nhưng bạn sẽ có dữ liệu của bạn được tổ chức thành một cây nhị phân và tuyến tính. – kdubs

Trả lời

2

tôi đã không đi qua kiểu tìm kiếm hai giai đoạn trước đây, do đó, không biết cho dù nó có một cái tên nổi tiếng. Tôi có thể, tuy nhiên, đề xuất một phương pháp để làm thế nào nó có thể được thực hiện.

Giả sử bạn đã chạy giai đoạn đầu tiên và không tìm thấy kết quả phù hợp.

Bạn có thể thực hiện giai đoạn thứ hai bằng một cặp tìm kiếm nhị phân và một bộ so sánh đặc biệt. Các tìm kiếm nhị phân sẽ sử dụng nguyên tắc tương tự như bisect_left and bisect_right. Bạn sẽ không thể sử dụng các hàm đó trực tiếp vì bạn sẽ cần một trình so sánh đặc biệt, nhưng bạn có thể sử dụng chúng làm cơ sở cho việc triển khai của bạn.

Bây giờ để so sánh. Khi so sánh phần tử danh sách x với phím tìm kiếm k, trình so sánh sẽ chỉ sử dụng x[:len(k)] và bỏ qua phần còn lại của x. Vì vậy, khi tìm kiếm "Peter", tất cả Peters trong danh sách sẽ so sánh bằng với khóa. Do đó, bisect_left() đến bisect_right() sẽ cung cấp cho bạn phạm vi chứa tất cả Peters trong danh sách.

Tất cả điều này có thể được thực hiện bằng cách sử dụng các so sánh O(log n).

+0

Sự so sánh đầu tiên vẫn chỉ là một sự chia cắt thẳng, mặc dù, phải không? Vì vậy, tìm trường hợp đầu tiên của Peter (hoặc chỉ là bisection ban đầu) và sau đó sử dụng so sánh để chỉ phù hợp tuy nhiên nhiều ký tự có liên quan đến truy vấn ... – DeaconDesperado

+0

@DeaconDesperado: Phương pháp đầu tiên tìm kiếm một kết hợp chính xác và trả về nhiều nhất một , trong khi thứ hai tìm kiếm một tiền tố phù hợp và trả về một phạm vi. Bạn có thể trộn và kết hợp các thuộc tính này là thích hợp cho ứng dụng của bạn ... – NPE

0

Trong tìm kiếm nhị phân của bạn, bạn nhấn một kết hợp chính xác HOẶC một khu vực nơi phù hợp sẽ là.
Vì vậy, trong trường hợp của bạn, bạn cần phải nhận được các ranh giới trên và dưới (hilo khi bạn gọi cho chúng) cho khu vực sẽ bao gồm Peter và trả về tất cả các chuỗi trung gian.

Nhưng nếu bạn đặt mục tiêu để làm một cái gì đó giống như chương trình từ tiếp theo của một từ mà bạn nên xem xét Tries thay vì BSTs

+0

Cảm ơn, tôi nghĩ rằng tôi hiểu những gì bạn đang nói ... tính toán hi và lo sẽ phải tính đến liệu tập hợp con có được tạo thành từ các kết quả phù hợp hay không. Và tôi hiểu ý của bạn về "từ tiếp theo" ... đã sử dụng cây hậu tố cho điều đó. – DeaconDesperado

+0

'các tính toán hi và lo sẽ phải đưa vào tài khoản có hay không các tập hợp con là hoàn toàn tạo thành các trận đấu tốt' Nó không phải là quá phức tạp vì các yếu tố đã được sắp xếp. Vì vậy, tất cả những gì bạn cần là tất cả các phần tử bên trong 'low'-'hi' – Cratylus

Các vấn đề liên quan