Tại sao tìm kiếm nhị phân nhanh hơn tìm kiếm ternary?


49

Tìm kiếm một mảng gồm các phần tử bằng cách sử dụng tìm kiếm nhị phân, trong trường hợp xấu nhất lặp đi lặp lại bởi vì, ở mỗi bước, chúng tôi cắt một nửa không gian tìm kiếm của chúng tôi. Thay vào đó, nếu thay vào đó, chúng tôi đã sử dụng 'tìm kiếm tạm thời', chúng tôi đã cắt đi hai phần ba không gian tìm kiếm của chúng tôi ở mỗi lần lặp, vì vậy trường hợp xấu nhất sẽ xảy ra lần lặp ...Nlog2Nlog3N<log2N

Có vẻ như tìm kiếm ternary nhanh hơn, vậy tại sao chúng ta sử dụng tìm kiếm nhị phân?


3
Không thể sử dụng cùng một lý do về tìm kiếm Đệ tứ? Hoặc thậm chí tìm kiếm thập phân ... hoặc bất cứ thứ gì lớn hơn 2.
d'ral'cop

4
vui lòng đọc về B + Cây
arunmoezhi

5
Tìm kiếm tuyến tính thường nhanh hơn tìm kiếm nhị phân trên các vấn đề từ nhỏ đến vừa trên phần cứng hiện đại, bởi vì nó kết hợp bộ nhớ cache và hầu như tất cả các nhánh được dự đoán chính xác.
Bút danh

2
Ngoài ra 2 * log_3 (N) = log_3 (N ^ 2) nếu nó nói lên trực giác của bạn.
PawelP

6
Hãy đặt điều này vào các thuật ngữ trực quan. Nếu sử dụng tìm kiếm dựa trên 3 nhanh hơn vì nó cắt không gian tìm kiếm nhiều hơn ở mỗi lần lặp, thì không sử dụng tìm kiếm dựa trên hàng triệu nhanh hơn? Nhưng bạn có thể dễ dàng thấy rằng trung bình bạn phải thực hiện 500.000 kiểm tra bên trong mỗi lần lặp để xác định lát cắt thứ 1 triệu có chứa mục tiêu. Rõ ràng, việc cắt không gian tìm kiếm trong một nửa mỗi lần lặp và không còn nữa, cung cấp cho bạn nhiều thông tin nhất trong một bước duy nhất, đáng tin cậy.
ErikE

Câu trả lời:


76

Nếu bạn áp dụng tìm kiếm nhị phân, bạn có nhiều so sánh. Nếu bạn áp dụng tìm kiếm ternary, bạn có nhiều so sánh, như trong mỗi bước, bạn cần thực hiện 2 so sánh để cắt không gian tìm kiếm thành ba phần. Bây giờ nếu bạn làm toán, bạn có thể quan sát rằng: Vì chúng tôi biết rằng , chúng tôi thực sự có được nhiều so sánh hơn với tìm kiếm tạm thời.

log2(n)+O(1)
2log3(n)+O(1)
2log3(n)+O(1)=2log(2)log(3)log2(n)+O(1)
2log(2)log(3)>1

Bằng cách: tìm kiếm -ary có thể làm cho rất nhiều ý nghĩa trong trường hợp nếu so sánh là khá tốn kém và có thể được song song, như sau đó, máy tính song song có thể được áp dụng.n

Lưu ý rằng đối số có thể được khái quát hóa để tìm kiếm -ary khá dễ dàng. Bạn chỉ cần chỉ ra rằng hàm là tăng đơn điệu cho các giá trị nguyên của .nf(k)=(k1)log(2)log(k)k


1
Và LHS là tuyến tính & RHS là logarit nên nó sẽ không giúp ích cho bất kỳ thứ tư hay gì hơn thế .... Giải thích hay .... Cảm ơn
Quảng trường trung bình

3
Chỉ vì mục đích hoàn chỉnh: lưu ý rằng một thước đo trừu tượng như số lượng so sánh phần tử có thể hoặc không thể chi phối thời gian chạy thực tế. Cụ thể, bạn có thể phải xem xét có bao nhiêu bộ nhớ cache mà bạn có khả năng nhận được trên các mảng dài với một trong hai tìm kiếm. (Ở đây, chúng trùng khớp. Tôi chỉ lưu ý điều này vì OP hỏi, "tại sao nó nhanh hơn?", Và trả lời rằng với một biện pháp trừu tượng có thể gây hiểu nhầm cho một số thuật toán.)
Raphael

10
Trong một tìm kiếm tạm thời, 1/3 thời gian bạn sẽ chỉ cần 1 so sánh (thực hiện so sánh thấp hơn: nếu ở phần ba thấp hơn, bạn không cần so sánh thứ hai). Điều đó làm cho ternary chỉ chậm hơn khoảng 5% thay vì 25% (trong thế giới này, trong đó chúng ta chỉ quan tâm đến số lượng so sánh). Tôi không chắc làm thế nào để khái quát hóa điều này với n-ary, mặc dù tôi nghi ngờ nó không bao giờ nhanh hơn nhị phân.
Aaron Dufour

2
@AaronDufour: Vì người ta có thể thực hiện tìm kiếm bậc bốn bằng cách so sánh với mục giữa trước và sau đó bỏ qua kết quả của các phép so sánh khác, cách duy nhất tìm kiếm bậc bốn có thể nhanh hơn nếu ba phép so sánh có thể được thực hiện song song rẻ hơn so với hai phép so sánh có thể được thực hiện tuần tự.
supercat

1
@AaronDufour Nhưng bạn đang khấu hao các yếu tố để tìm kiếm, và tôi không rõ tại sao điều đó lại ổn. Trong trường hợp xấu nhất, cả hai phép so sánh có thể được thực hiện ở mọi bước.
Sasho Nikolov

26

DCTLib đúng, nhưng quên toán học trong một giây.

Theo logic của bạn sau đó, n -ary nên là nhanh nhất. Nhưng nếu bạn nghĩ về nó, n -ary chính xác bằng một tìm kiếm lặp thông thường (chỉ lặp qua danh sách 1 trên 1, nhưng theo thứ tự ngược lại). Trước tiên, bạn chọn mục cuối cùng (hoặc bên cạnh cuối cùng) trong danh sách và so sánh giá trị đó với giá trị so sánh của bạn. Sau đó, bạn xóa mục đó khỏi danh sách của bạn, rồi chọn mục cuối cùng trong danh sách mới, đây chỉ là mục tiếp theo của giá trị cuối cùng trong mảng. Mỗi lần, bạn sẽ chỉ loại bỏ 1 giá trị tại một thời điểm cho đến khi bạn tìm thấy giá trị của mình.

Thay vào đó, bạn nên nghĩ về nó như thế này - làm cách nào để loại bỏ hầu hết các giá trị khỏi danh sách mỗi lần lặp? Trong một tìm kiếm nhị phân, bạn luôn loại bỏ một nửa danh sách. Trong một tìm kiếm tạm thời, có khả năng (thực tế là 33,33%) rằng bạn có thể loại bỏ 2/3 danh sách, nhưng có một cơ hội thậm chí còn lớn hơn (66,66%) rằng bạn sẽ chỉ loại bỏ 1/3 danh sách. để tính O (n), bạn cần xem xét trường hợp xấu nhất là 1/3, dưới 1/2. Khi bạn càng ngày càng gần n, nó càng trở nên tồi tệ hơn.

Không chỉ trường hợp xấu nhất sẽ được cải thiện với tìm kiếm nhị phân, mà thời gian trung bình của bạn cũng sẽ được cải thiện. Nhìn vào giá trị mong đợi (trung bình chúng ta có thể loại bỏ phần nào của danh sách), chúng tôi sử dụng công thức này:

(P_lower) x (phần chúng ta có thể xóa nếu thấp hơn) + (P_higher) x (phần chúng ta có thể xóa nếu cao hơn) = E

Đối với tìm kiếm nhị phân, đây là .5x.5 + .5x.5 = .5 (chúng tôi luôn xóa một nửa danh sách). Đối với các tìm kiếm ternary, giá trị này là .666x.333 + .333x.666 = 0.44 hoặc ở mỗi bước, chúng tôi sẽ chỉ loại bỏ 44% danh sách, làm cho nó kém hiệu quả hơn so với tìm kiếm nhị phân, trung bình. Giá trị này đạt cực đại ở mức 1/2 (một nửa danh sách) và giảm khi bạn càng gần n (lặp lại) và 0 (lặp thường xuyên).

Ok, vì vậy tôi đã nói dối..có một chút toán học liên quan, nhưng tôi hy vọng điều đó có ích!


1
Đây là một câu trả lời tuyệt vời.
The_Sympathizer

Phân tích ranh giới Ya giúp hiểu toán khó! Tìm kiếm tuần tự n-ary có cùng chi phí tìm kiếm tuyến tính O (n).
shuva

-2

Xin lưu ý đối số so sánh log (N) vs 2 log (N) dựa trên cách giải thích ngây thơ của thuật toán. Nếu tôi thực sự ngồi xuống và viết cái này trong x86, kết quả sẽ bị đảo ngược. Vấn đề là việc sử dụng số nguyên cho các trường hợp thử nghiệm kết hợp với trình biên dịch không đủ thông minh không thể loại bỏ các so sánh dư thừa. Thử lại với các chuỗi và một hàm so sánh chuỗi thích hợp và mã hóa nó để gọi hàm so sánh một lần trên mỗi vòng lặp và bạn sẽ thấy việc tìm kiếm ternary nhanh hơn một lần nữa.


2
Tất nhiên tìm kiếm ternary sẽ nhanh hơn nếu bạn có thể làm điều đó chỉ với một lần so sánh trên mỗi lần lặp. Nhưng, bất kể là chuỗi hay số nguyên, bạn không thể.
FrankW

Các so sánh sẽ không dư thừa và vấn đề không liên quan gì đến trình biên dịch. Để chia không gian tìm kiếm thành ba phần, bạn cần 2 so sánh. Trong tìm kiếm nhị phân, bạn chỉ cần so sánh với phần tử ở giữa và sau đó bạn sẽ biết một nửa không gian tìm kiếm mà kết quả sẽ nằm ở đâu. Với tìm kiếm tạm thời, bạn cần so sánh với phần tử 1/3 trong suốt quá trình liệt kê VÀ một phần hai trong số các cách thông qua danh sách. Loại dữ liệu bạn đang so sánh hoặc ngôn ngữ bạn đang sử dụng là không liên quan. Cấp, nếu mục nằm trong lần thứ 3, bạn có thể dừng lại sau 1 lần so sánh.
đăng lại

2
Trên một số nền tảng, tìm kiếm tạm thời có thể nhanh hơn do cho phép CPU có nhiều thời gian hơn để tìm nạp các toán hạng từ RAM trước khi cần chúng để so sánh. Nhưng điều đó phụ thuộc hoàn toàn vào nền tảng được sử dụng và độ trễ và bộ nhớ cache của nó.
jpa

1
Darn it - định nghĩa sai của tìm kiếm ternary.
Joshua
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.