Tải bản đầy đủ (.doc) (2 trang)

Thuật toán tìm kiếm RABIN

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (98.25 KB, 2 trang )

Thuật toán Rabin-Karp
Thuật toán Rabin-Karp là một trong những phương pháp tìm kiếm chuỗi. Ý tưởng là chúng ta sẽ
khai thác một vùng nhớ lớn bằng cách xem mỗi đoạn M-ký tự có thể có của văn bản như là một
khoá (key) trong một bảng băm chuẩn. Nhưng không cần thiết phải giữ một bảng băm tổng thể,
vì bài toán được cài đặt sao cho chỉ một khoá là đang được tìm kiếm; việc mà ta cần làm là đi
tính hàm băm cho M ký tự từ văn bản vì nó chỉ đơn giản là kiểm tra xem chúng có bằng với mẫu
hay không. Với hàm băm: h(k) = k mod q, ở đây q (kích thước bảng) là một số nguyên tố lớn.
Trong trường hợp này, không có gì được chứa trong bảng băm, vì vậy q có thể được cho giá trị
rất lớn.
Phương pháp này dựa trên việc tính hàm băm cho vị trí i trong văn bản, cho trước giá trị tại
ví trí i-1 của nó, và suy ra hoàn toàn trực tiếp từ công thức toán học. Giả sử rằng ta dịch M
ký tự thành số bằng cách nén chúng lại với nhau trong một từ (word) của máy, mà ta xem
như một số nguyên. Điều này ứng với việc ghi các ký tự như các con số trong một hệ
thóng cơ số d, ở đây d là số ký tự có thể có. Vì vậy số ứng với a[i..i+M-1] là
x = a[i]d
M-1
+ a[i+1]d
M-2
+ …+ a[i+M-1]
Và có thể giả sử rằng ta biết giá trị của h(x) = x mod q. Nhưng dịch (shift) một vị trí sang
phải trong văn bản tương ứng với việc thay x bởi (x - a[i]d
M-1
)d + a[i+M].
Một tính chất cơ bản của phép toán mod là ta có thể thực hiện nó bất kỳ lúc nào trong các
phép toán này và vẫn nhận được cùng câu trả lời. Cách khác, nếu ta lấy phần dư khi chia
cho q sau mỗi một phép toán số học (để giữ cho các số mà ta đang gặp là nhỏ), thì ta sẽ
nhận được cùng câu trả lời như thể ta đã thực hiện tất cả các phép toán học, sau đó lầy
phần dư khi chia cho q.
Điều này dẫn tới một thuật toán đối sánh mẫu rất đơn giản được cài đặt dưới đây:

fuction rksearch: integer;


const q=33253586; d = 32;
var h1, h2, dM, i: integer;
begin
dM:= 1;
for i:=1 to M-1 do dM:= (d*dM) mod q;
h1: = 0;
for i: = 1 to M do h1:= (h1*d+index(p[i])) mod q;
h2: = 0;
for i:= 1 to M do h2:= (h2*d + index (a[i])) mod q;
i: = 1;
while (h1 <> h2) and(i<=N-M) do
begin
h2:= (h2+d*q-index(a[i])*dM) mod q;
h2:= (h2*d+index(a[i+M])) mod q;
i:= i+1;
end;
rksearch:= i;
end;
Chương trình giả định dùng hàm index (function index(c: char): integer; hàm trả về 0 đối
với các khoảng trắng và i đối với ký tự thứ i của bảng chữ cái) nhưng d = 32 để cho hiệu
quả (các phép nhân có thể được càiđặt như các phép dịch bit).
Đầu tiên chương trình tính giá trị h1 cho mẫu, sau đó tới giá trị h2 cho M ký tự đầu tiêncảu
văn bản (nó cũng tính giá trị của d
M-1
mod q trong biến dM). Sau đó nó tiến hành công việc
qua chuỗi văn bản, dùng đến kỹ thuật ở trên để tính hàm băm cho M ký tự với h1. Số
nguyên tố q được chọn càng lớn càng tốt, nhưng đủ nhỏ sao cho (d+1)*q không gây ra tràn
(overflow): điều này cần ít phép mod hơn nếu ta dùng số nguyên tố lớn nhất biểu diễn
được (một giá trị d*q phụ trợ được cộng thêm vào trong khi tính h2 để bảo đảm rằng mọi
đại lượng vẫn còn là dương để cho phép toán mod có thể thực hiện được).

*** Phép đối sánh mẫu Rabin-Karp gần như là tuyến tính.
Thuật toán này hiển nhiên thực hiện theo thời gian tỉ lệ với M+N, nhưng chú ý là nó chỉ
thực sự đi tìm một vị trí trong văn bản có cùgn giá trị băm với mẫu. Để cho chắc chắn, ta
nên thực sự tiến hành so sánh trực tiếp văn bản đó với mẫu. Tuy nhiên, việc sử dụng giá trị
rất lớn của q, được biến thành dương bởi các phép toán mod và bởi sự kiện làta không cần
duy trì bảng băm thực sự, đã khiến cho rất khó xảy ra một sự đụng độ. Về mặt lý thuyết,
thuật toán này có thể vẫn thực hiện theo O(NM) bước trong trường hợp xấu nhất ( không
đáng tin cậy), nhưng trong thực tế có thể dựa vào thuật toán để thực hiện khoảng N+M
bước.

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×