OK, vì vậy tôi không có vẻ như một thằng ngốc Tôi sẽ nói rõ hơn vấn đề / yêu cầu:
- Kim (mẫu) và haystack (văn bản để tìm kiếm) đều là các chuỗi kết thúc null kiểu C. Không có thông tin chiều dài được cung cấp; nếu cần, nó phải được tính toán.
- Hàm sẽ trả về một con trỏ cho kết quả khớp đầu tiên hoặc
NULL
nếu không tìm thấy kết quả khớp nào. - Trường hợp thất bại không được phép. Điều này có nghĩa là bất kỳ thuật toán nào có yêu cầu lưu trữ không cố định (hoặc hằng số lớn) sẽ cần phải có trường hợp dự phòng cho lỗi phân bổ (và hiệu suất trong chăm sóc dự phòng do đó góp phần vào hiệu suất trong trường hợp xấu nhất).
- Việc thực hiện là ở C, mặc dù một mô tả tốt về thuật toán (hoặc liên kết đến như vậy) mà không có mã cũng tốt.
... cũng như những gì tôi muốn nói là "nhanh nhất":
- Xác định
O(n)
trong đón
= chiều dài haystack. (Nhưng có thể sử dụng các ý tưởng từ các thuật toán thông thườngO(nm)
(ví dụ: băm) nếu chúng được kết hợp với một thuật toán mạnh hơn để đưa raO(n)
kết quả xác định ). - Không bao giờ thực hiện (có thể đo lường được; một vài đồng hồ đôi,
if (!needle[1])
v.v.) không tệ hơn thuật toán vũ phu ngây thơ, đặc biệt là trên các kim rất ngắn có khả năng là trường hợp phổ biến nhất. (Chi phí tiền xử lý nặng vô điều kiện là không tốt, vì đang cố gắng cải thiện hệ số tuyến tính cho kim bệnh lý với chi phí của kim có khả năng.) - Đưa ra một kim và cỏ khô tùy ý, hiệu suất tương đương hoặc tốt hơn (không quá thời gian tìm kiếm dài hơn 50%) so với bất kỳ thuật toán được triển khai rộng rãi nào khác.
- Ngoài những điều kiện này, tôi còn để lại định nghĩa về kết thúc mở "nhanh nhất". Một câu trả lời tốt sẽ giải thích lý do tại sao bạn xem xét phương pháp bạn đề xuất "nhanh nhất".
Việc triển khai hiện tại của tôi chạy chậm hơn khoảng 10% và nhanh hơn 8 lần (tùy thuộc vào đầu vào) so với triển khai Hai chiều của glibc.
Cập nhật: Thuật toán tối ưu hiện tại của tôi như sau:
- Đối với kim có chiều dài 1, sử dụng
strchr
. - Đối với các kim có độ dài 2-4, sử dụng các từ máy để so sánh 2-4 byte cùng một lúc như sau: Tải trước kim trong số nguyên 16 hoặc 32 bit với bithifts và chu kỳ byte cũ / byte mới từ haystack trong mỗi lần lặp . Mỗi byte của haystack được đọc chính xác một lần và phát sinh một kiểm tra đối với 0 (cuối chuỗi) và một so sánh 16 hoặc 32 bit.
- Đối với kim có độ dài> 4, sử dụng thuật toán Hai chiều với bảng dịch chuyển xấu (như Boyer-Moore) chỉ áp dụng cho byte cuối cùng của cửa sổ. Để tránh chi phí khởi tạo bảng 1kb, sẽ là tổn thất ròng đối với nhiều kim có độ dài vừa phải, tôi giữ một mảng bit (32 byte) đánh dấu các mục trong bảng dịch chuyển được khởi tạo. Các bit không được đặt tương ứng với các giá trị byte không bao giờ xuất hiện trong kim, trong đó có thể dịch chuyển toàn bộ chiều dài kim.
Những câu hỏi lớn còn lại trong tâm trí tôi là:
- Có cách nào để sử dụng tốt hơn bảng dịch chuyển xấu? Boyer-Moore sử dụng nó tốt nhất bằng cách quét ngược (từ phải sang trái) nhưng Two-Way yêu cầu quét từ trái sang phải.
- Hai thuật toán ứng cử viên khả thi duy nhất tôi tìm thấy cho trường hợp chung (không có điều kiện hiệu năng ngoài bộ nhớ hoặc bậc hai) là Kết hợp hai chiều và Chuỗi trên bảng chữ cái được đặt hàng . Nhưng có những trường hợp dễ phát hiện trong đó các thuật toán khác nhau sẽ là tối ưu? Chắc chắn nhiều thuật toán
O(m)
(trong đóm
là chiều dài kim) trong thuật toán không gian có thể được sử dụng chom<100
hoặc như vậy. Cũng có thể sử dụng các thuật toán là phương pháp bậc hai trong trường hợp xấu nhất nếu có một phép thử dễ dàng đối với các kim chỉ yêu cầu thời gian tuyến tính.
Điểm thưởng cho:
- Bạn có thể cải thiện hiệu suất bằng cách giả sử kim và cỏ khô đều là UTF-8 được hình thành tốt không? (Với các ký tự có độ dài byte khác nhau, trạng thái được định dạng tốt sẽ áp đặt một số yêu cầu căn chỉnh chuỗi giữa kim và haystack và cho phép dịch chuyển 2-4 byte tự động khi gặp phải byte đầu không khớp. Nhưng những ràng buộc này sẽ mua cho bạn nhiều / bất cứ điều gì ngoài những gì tính toán hậu tố tối đa, dịch chuyển hậu tố tốt, vv đã cung cấp cho bạn các thuật toán khác nhau?)
Lưu ý: Tôi nhận thức rõ về hầu hết các thuật toán ngoài kia, chỉ là chúng không hoạt động tốt như thế nào trong thực tế. Đây là một tài liệu tham khảo tốt để mọi người không tiếp tục cung cấp cho tôi các tài liệu tham khảo về các thuật toán dưới dạng nhận xét / câu trả lời: http://www-igm.univ-mlv.fr/~lecroq/opes/index.html
strstr
như một điều gì đó cho lần sau, vì vậy tôi thực sự đã loay hoay đọc đúng bài báo bạn liên kết, nhưng nghe có vẻ rất hứa hẹn. Cảm ơn và xin lỗi vì đã không quay lại với bạn.