Một tóm tắt nhanh đầu tiên. Chúng tôi đang tìm kiếm một mô hìnhP[ 1 ... m ] trong một chuỗi S[ 1 ... n ]. Thuật toán Rabin-Karp thực hiện điều này bằng cách xác định hàm bămh. Chúng tôi tính toánh ( P) (đó là hàm băm của mẫu) và so sánh nó với h ( S[ 1 ... m ] ), h ( S[ 2 ... m + 1 ] )và như thế. Nếu chúng ta tìm thấy một hàm băm phù hợp, thì đó là một chuỗi con phù hợp tiềm năng.
Hiệu quả của thuật toán phụ thuộc vào khả năng tính toán h ( S[ R + 1 ... s + 1 ] ) hiệu quả từ h ( S[ R ... s ] ). Điều này được gọi là "băm lăn". Lưu ý rằng bất kỳ hàm băm cán hiệu quả nào cũng được, và đó vẫn là Rabin-Karp. Câu hỏi mà bạn đang hỏi là một lựa chọn cụ thể của hàm băm, nơi bạn sử dụng:
h ( S[ R ... s ] ) =Σtôi = rSS[ i ]ps - tôimod q
Trong đó là số nguyên tố có cùng độ lớn với kích thước của bộ ký tự và là một số nguyên tố khác xác định mức độ chính xác của phạm vi của hàm băm, thường có cùng độ lớn với từ máy chia cho kích thước bộ ký tự. Nếu tôi đang đọc chính xác, bạn sẽ hỏi tại sao phải là số nguyên tố.pqq
Trong thực tế, đây là một câu hỏi tổng quát hơn. Trong rất nhiều tài liệu cũ (và hiện tại) về băm, lời khuyên là hàm băm nên được lấy modulo một số nguyên tố (ví dụ: bảng băm nên có kích thước nguyên tố).
Để hàm băm trở nên hữu ích nhất có thể, phạm vi của nó cần phải tương đối đồng đều, ngay cả khi tên miền của nó không. Văn bản ngôn ngữ tự nhiên (giả sử) không có phân phối tần số thống nhất, nhưng giá trị băm nên có.
Nếu là số nguyên tố, thì rất nhiều số khác tương đối nguyên tố với nó, và đặc biệt, tổng (đặc biệt nếu cũng là số nguyên tố!). Điều này làm cho phân phối tần số của các giá trị băm đồng đều hơn, mặc dù hàm băm tương đối yếu.qp
Điều quan trọng là phải hiểu rằng chúng tôi làm điều này bởi vì hàm băm yếu. Nếu hàm băm mạnh hơn, lấy phần còn lại khi chia cho số nguyên tố là không cần thiết; bạn có thể, ví dụ, lấy phần còn lại khi chia cho công suất hai, sẽ là một hoạt động mặt nạ bit rẻ hơn nhiều. Tuy nhiên, thật khó để thiết kế các hàm băm cán mạnh, đủ rẻ để thực hiện cho mọi ký tự đầu vào trong thuật toán Rabin-Karp.
Một cái gì đó đáng để chỉ ra rằng kỹ thuật "phần còn lại của một nguyên tố" này thường được sử dụng trong nhiều ứng dụng băm, nhưng lời khuyên này không phù hợp với phần cứng hiện đại. Lời khuyên này có ý nghĩa một lần, bởi vì trong khi hướng dẫn phân chia số nguyên cuối cùng luôn đắt tiền, thì các thao tác mà bạn đã sử dụng để tính hàm băm của mình, chẳng hạn như nhân số nguyên. Trên các CPU hiện đại, việc phân chia số nguyên sẽ tốn kém hơn nhiều so với phép nhân số nguyên.
Hệ số nhân bộ cộng mang theo hiện đại được sắp xếp đầy đủ, do đó bạn có thể có một số hướng dẫn như vậy được thực thi cùng một lúc. Các bộ chia hiện đại sử dụng thuật toán SPH hoặc Goldschmidt, là các chu trình đa chu kỳ và không thể thực hiện được. Bộ chia Goldschmidt cũng gắn kết đơn vị nhân, làm cho hiệu suất đạt được thậm chí còn lớn hơn.
Tôi đã có các chương trình trong đó hướng dẫn phân chia này là nút cổ chai và điều khó chịu là nó bị ẩn trong thư viện chuẩn.
Trên CPU hiện đại, đáng sử dụng hàm băm tinh vi hơn được xây dựng từ các hoạt động có thể kết hợp hoàn toàn (ví dụ: bội số hoặc thậm chí tra cứu bảng) và sử dụng các bảng băm có sức mạnh bằng hai, vì vậy thao tác modulo là mặt nạ bit. Làm bất cứ điều gì để tránh hoạt động phân chia đó.
Chỉ không dành cho Rabin-Karp.