Thuật toán KMP được trình bày chi tiết trong 4, 5, 14 nội dung như sau:
Duyệt từ trái sang phải trên S và P, mỗi lần một ký tự. Gọi con trỏ trên P là i, con trỏ trên S là j. Giả sử đã xuất hiện khúc đầu độ dài i - 1 của mẫu P và việc khớp mẫu thất bại tại vị trí j trên S, có nghĩa:
P1P2…Pi -1 Sj - i + 1Sj - i + 2…S j - 1 và Pi Sj
Khi đó cần phải bắt đầu đối sánh mẫu từ vị trí j - h +1 trên S (trường hợp xấu nhất h = i - 1 trong thuật toán Brute - Force). Nếu tồn tại h > 0 sao cho h - 1 ký tự đầu của mẫu khớp với h - 1 ký tự cuối của đoạn S(j - 1) hay có nghĩa đã khớp với h - 1 ký tự cuối của P(i - 1) thì ta có thể bỏ
Số hóa bởi Trung tâm Học liệu – Đại học Thái Nguyên http://www.lrc-tnu.edu.vn 19 h=next[i] S P P i j m m +1 j h=next[m+1] P S P qua h - 1 phép so sánh và tiếp tục so sánh 2 ký tự Ph và Sj (hình 1.1). Do h phụ thuộc vào i nên ký hiệu h = nexti, i = 1,…,m.
?
Hình 1.1. Ý nghĩa của mảng next
Nếu Sj Ph thì phải tiếp tục lùi con trỏ trên mẫu. Để khắc phục nhược điểm do tình huống này gây ra, cần cố gắng tìm h sao cho Ph có nhiều khả năng bằng Sj. Vì Sj Pi nên cần tìm h thoả mãn Ph Pi .
Trong KMP, khi i > m ta được một xuất hiện của mẫu bắt đầu từ vị trí j - m trên S. Để tìm xuất hiện tiếp theo, nếu bắt đầu đối sánh từ P1
và Sj thì có thể bỏ sót mẫu khi có mẫu xuất hiện lồng nhau. Vì vậy, khi con trỏ trên S dừng ở vị trí j, cần trượt mẫu đi một số vị trí sao cho h - 1 ký tự đầu của mẫu khớp với h - 1 ký tự cuối của S(j - 1) hay chính là khớp với h - 1 ký tự cuối của P(m). Do đó cần mở rộng mảng next với i = m + 1. (Hình 1.2).
Số hóa bởi Trung tâm Học liệu – Đại học Thái Nguyên http://www.lrc-tnu.edu.vn
20
Như vậy, với mỗi vị trí i trên P, i = 1..m + 1, cần xác định next i
thoả mãn:
+ nexti là số h lớn nhất sao cho h - 1 ký tự đầu của mẫu khớp với h - 1 ký tự cuối của P(i- 1).
+ Pi Pnext i
(để có nextm + 1, tưởng tượng như đã bổ sung thêm ký tự vào cuối P, với là một ký tự không xuất hiện trong P).
Ví dụ 1.1. Với P = aababaab ta có bảng next như sau:
i 1 2 3 4 5 6 7 8 9
next[i] 0 0 2 0 2 0 0 2 4
Thuật toán 1.1. Xây dựng mảng next
procedure Initnext(); var i, j: Integer; begin i: = 1; j: = next 1: = 0; while i< = m do begin
while j > 0 and Pi P j do j: = next j; i: = i + 1; j: = j + 1;
if ( i < = m) and (Pi = P j) then next i := next j else next i : = j;
end; end;
Thuật toán 1.2. KMP tìm nhiều lần lặp mẫu
Số hóa bởi Trung tâm Học liệu – Đại học Thái Nguyên http://www.lrc-tnu.edu.vn
21
Tìm mọi vị trí xuất hiện xâu mẫu P độ dài m trong xâu đích S độ dài n, đồng thời thống kê tần suất xuất hiện mẫu
var i, j: Integer; counter: Integer; begin Initnext (); i:= 1; j:= 1; counter: = 0; repeat while i < = m and j < = n do begin
while (i > 0) and (Sj Pi) do i: = next i; i: = i + 1; j = j + 1;
end;
if( i > m) then begin
Ghi nhận vị trí xuất hiện mẫu là j - m; counter: =counter + 1; end; i: = next m + 1; until j > n; Ghi nhận counter; end;
Độ phức tạp của thuật toán 4, 5
- Pha tiền xử lý mẫu: Độ phức tạp thời gian và không gian để xây dựng bảng next là O(m).
Số hóa bởi Trung tâm Học liệu – Đại học Thái Nguyên http://www.lrc-tnu.edu.vn
22