Xét một dạng sửa đổi mô hình DFA để chấp nhận không, một hoặc nhiều hơn một phép chuyển từ một trạng thái trên cùng một ký hiệu nhập. Mô hình mới này gọi là ôtômát hữu hạn không đơn định (NFA - Nondeterministic Finite Automata).
Một chuỗi ký hiệu nhập a1 a2 ... an đƣợc chấp nhận bởi một NFA nếu có tồn tại một chuỗi các phép chuyển, tƣơng ứng với chuỗi nhập, từ trạng thái bắt đầu đến trạng thái kết thúc. Chẳng hạn, chuỗi 01001 đƣợc chấp nhận bởi ôtômát trong hình dƣới đây vì có chuỗi phép chuyển qua các trạng thái q0, q0, q0, q3, q4, q4 có nhãn tƣơng ứng là 0,1, 0, 0, 1. NFA này chấp nhận tất cả các chuỗi có hai số 0 liên tiếp hoặc hai số 1 liên tiếp.
Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/
Hình 1.3. Sơ đồ của một NFA
Có thể xem ôtômát hữu hạn đơn định là một trƣờng hợp đặc biệt của NFA, trong đó mỗi trạng thái chỉ có duy nhất một phép chuyển trên mỗi ký hiệu nhập. Vì thế trong DFA, với một chuỗi nhập w và trạng thái q, chỉ có đúng một đƣờng đi nhãn w bắt đầu từ q. Để xác định chuỗi w có đƣợc chấp nhận bởi DFA hay không chỉ cần kiểm tra đƣờng đi này. Nhƣng đối với NFA, có thể có nhiều đƣờng đi có nhãn là w, và do đó tất cả phải đƣợc kiểm tra để thấy có hay không có đƣờng đi tới trạng thái kết thúc.
Tƣơng tự nhƣ DFA, NFA cũng hoạt động với một bộ điều khiển hữu hạn đọc trên băng nhập. Tuy nhiên, tại mỗi thời điểm, bộ điều khiển có thể chứa một số bất kỳ trạng thái. Khi có sự lựa chọn trạng thái kế tiếp, chẳng hạn nhƣ từ trạng thái q0 trên k hiệu nhập 0 ở hình trên, ta tƣởng tƣợng nhƣ có các bản sao của ôtômát đang thực hiện đồng thời. Mỗi trạng thái kế tiếp mà ôtômát có thể chuyển đến sẽ tƣơng ứng với một bản sao của ôtômát mà tại đó bộ điều khiển đang chứa trạng thái đó.
Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/
Hình 1.4. Di chuyển chuỗi
Một cách hình thức ta định nghĩa ôtômát hữu hạn không đơn định NFA là một bộ 5 thành phần (Q, Σ, δ, q0, F) trong đó Q, Σ, q0 và F có ý nghĩa nhƣ trong DFA, nhƣng δ là hàm chuyển ánh xạ từ Q × Σ → 2Q
.
Khái niệm δ(q, a) là tập hợp tất cả các trạng thái p sao cho có phép chuyển trên nhãn a từ trạng thái q tới p.
Để thuận tiện trong việc mô tả hoạt động ôtômát trên chuỗi, ta mở rộng hàm chuyển δ ánh xạ từ Q × Σ* → 2Q nhƣ sau:
1. δ(q, ε) = {q}
2. δ(q, wa) = { p | có một trạng thái r trong δ(q, w) mà p thuộc δ(r, a)} = δ(δ(q, w), a)
3. δ(P, w) = ∪q ∈ P δ(q, w) , ∀P ⊆ Q.
Ngôn ngữ L(M), với M là ôtômát hữu hạn không đơn định NFA (Q, Σ, δ, q , F) là tập hợp: L(M) = {w | δ(q0, w) có chứa một trạng thái trong F}
Ví dụ: Xét sơ đồ chuyển của hình 2.3. Theo khái niệm hình thức, ta có: NFA M ({q0, q1, q2, q3, q4}, {0, 1}, δ, q0}) với hàm chuyển δ nhƣ sau:
Bảng 1.2. Ví dụ hàm chuyển trạng thái δ của NFA
Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/ Ta có: δ (q0, 0) = {q0, q3} δ (q0, 01) = δ(δ(q0, 0),1) = δ({q0, q3},1) = δ (q0, 1) ∪ δ (q3, 1) = {q0, q1} Tƣơng tự , ta có thể tính : δ (q0, 010) = {q0, q3} δ (q0, 0100) = {q0, q3, q4} và δ (q0, 01001) = {q0, q1, q4} Do q4∈ F nên w ∈ L (M). 1.6.2. Otomat khớp chuỗi 1.6.2.1. Giới thiệu
So khớp chuỗi là thực hiện tìm kiếm và xác định chính xác vị trí xuất hiện của đối tƣợng đƣợc chọn, còn gọi là mẫu trong văn bản. Văn bản và các mẫu là các chuỗi ký tự, chúng là những chuỗi gồm hữu hạn các ký tự thuộc tập hữu hạn các ký tự trong tập hữu hạn các ký tự chữ cái.
Ta hình thức hoá bài toán so khớp chuỗi nhƣ sau: coi văn bản là một mảng T[1..n] có chiều dài n và khuôn mẫu là một mảng P[1..m] có chiều dài m; các thành phần của T và P là các ký tự đƣợc rút từ một bảng chữ cái hữu hạn ∑. Ví dụ, ta có thể có ∑ = {0,1} hoặc ∑ ={a,b,....,z}. Các mảng ký tự P và T thƣờng đƣợc gọi là các chuỗi ký tự. Ta nói rằng một chuỗi w là tiền tố (hậu tố) của một chuỗi x, ký hiệu là w ⊂ x (w ⊃ x), nếu x = wy (x = yw), với y là một chuỗi nào đó. Để ngắn gọn, ta kí hiệu Pk để thể hiện tiền tố k - ký tự P[1..k] của khuôn mẫu P[1..m].
Ta nói rằng khuôn mẫu P xảy ra với khoá chuyển s trong văn bảnT (hoặc, theo tƣơng đƣơng, nói rằng khuôn mẫu P xảy ra bắt đầu tại vị trí s + i trong văn bản T) nếu 0 ≤ s ≤ n-m và T[s + 1..s + m] = P[1..m] (nghĩa là, nếu T[s+j] = P[j], với 1 ≤ j ≤ m). Bài toán so khớp chuỗi là bài toán tìm tất cả các khoá chuyển hợp lệ với nó một khuôn mẫu P đã cho xảy ra trong một văn bản T đã cho.
Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/
abcabaabcabac, tại khoá chuyển s = 3. Với bài toán này, rõ ràng ta có một cách làm đơn giản là tìm tất cả các khoá chuyển hợp lệ dùng một vòng lặp kiểm tra điều kiện P[1..m] = T[s+1..s+m] với n - m + 1 giá trị có thể của s.
Procedure NAIVE-STRING-MATCHER(T,P) Begin
for s := 0 to n - m do
if P[1..m] = T[s+1..s+m] then
write(‘khuôn mẫu xảy ra với khoá chuyển’, s +1) End;
Hình1.5. Ví dụ so khớp chuỗi
Hình trên minh họa phép toán của bộ so khớp chuỗi đơn giản với khuôn mẫu P = aab và văn bản T = acaabc; các vạch dọc nối các vùng tƣơng ứng với tìm thấy so khớp (đƣợc tô bóng), và một vạch zích zắc nối ký tự không so khớp đầu tiên tìm thấy, nếu có. Một trƣờng hợp xuất hiện của khuôn mẫu đƣợc tìm thấy, tại khoá chuyển s = 2, trong hình (c).
Đánh giá: Thủ tục NAIVE-STRING-MATCHER có độ phức tạp O((n- m+1)m) trong trƣờng hợp xấu nhất. Nhƣ sẽ thấy, NAIVE-STRING-MATCHER không phải là một thủ tục tối ƣu cho bài toán này. Do đó việc sử dụng Otomat so khớp chuỗi hiệu quả hơn vì chúng xét mỗi ký tự văn bản chính xác một lần.
Có một otomat so khớp chuỗi cho mọi khuôn mẫu P: otomat này phải đƣợc khởi tạo từ khuôn mẫu trƣớc khi dùng nó để tìm trong chuỗi văn bản. Hình 1.6 minh họa sơ đồ chuyển tiếp trạng thái của otomat so khớp chấp nhận tất cả các chuỗi kết thúc bởi chuỗi ababaca. Trạng thái 0 là trạng thái đầu, và trạng thái 7 là trạng thái chấp nhận duy nhất. Một cạnh có hƣớng từ trạng thái i đến trạng thái j đƣợc gắn nhãn a biểu diễn δ(i, a) = j. Các cạnh sang phải hình thành “cột
Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/
sống” của otomat, đƣợc vẽ đậm trong hình, tƣơng ứng với các lần so khớp thành công giữa khuôn mẫu và các ký tự đầu vào. Các cạnh sang phải tƣơng ứng các lần so khớp thất bại. Có vài cạnh tƣơng ứng với các lần so khớp thất bại không đƣợc nêu; theo quy ƣớc, nếu một trạng thái i không có cạnh đi ra đƣợc gắn nhãn a với một a ∈ ∑, thì δ(i, a) = 0. Hình (b) là hàm chuyển tiếp tƣơng ứng δ, và chuỗi khuôn mẫu P = ababaca. Các ô tƣơng ứng với các lần so khớp thành công giữa khuôn mẫu và các ký tự đầu vào đƣợc nêu ở dạng tô bóng. Hình (c) minh họa phép toán của otomat trên văn bản T = abababacaba. Dƣới mỗi ký tự văn bản T[i] đƣợc gán một trạng thái mà otomat nằm trong đó, sau khi xử lý tiền tố Ti. Một lần xuất hiện của khuôn mẫu đƣợc tìm thấy, kết thúc tại vị trí 9.
Hình 1.6. Ví dụ otomat so khớp chuỗi
1.6.2.2. Thuật toán xây dựng Otomat so khớp chuỗi
Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/ P[1..m] nhƣ sau: Procedure COMPUTE-TRANSITION-FUNCTION(P, ∑) Begin m : = length(P) For q : = 0 to m do For mỗi ký tự a ∈ ∑ do Begin k : = min(m+1, q+2); repeat k : = k – 1
until (Pk là hậu tố của Pqa); δ(q, a) : = k
End; End;
Trong thủ tục trên, ta xét tất cả các trạng thái q và các ký tự a; giá trị δ(q, a) là số k lớn nhất sao cho Pk là hậu tố của Pqa. Giá trị lớn nhất của k là min (m, q+1), sau đó giảm k cho đến khi thỏa mãn. Thời gian thực hiện của hàm trên là O(m3|∑|), với |∑| là số lƣợng kí tự trong ∑. Sau đây là thủ tục xây dựng otomat:
Procedure FINITE-AUTOMATON-MATCHER(T, δ, m) Begin n : = length(T) q : = 0; for i : = 1 to n do Begin q : = δ(q, T[i]);
if q = m then writeln(‘khuôn mẫu xảy ra với khoá chuyển:’,i - m); End; End;
Đánh giá: tổng thời gian thực hiện để tìm tất cả các lần xuất hiện của một khuôn mẫu có chiều dài m trong một văn bản có chiều dài n trên một bảng chữ cái ∑ là O(n + m|∑|).
Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/
1.7. Kết luận chƣơng
Trên đây là một số kiến thức cơ bản về so khớp chuỗi, thông qua đó ta có thể nắm bắt đƣợc các kiến thức nền tảng về so khớp chuỗi, các hƣớng tiếp cận, các dạng so khớp và một số thuật toán so mẫu. Đây là những kiến thức cơ sở để tiếp tục tìm hiểu, nghiên cứu về thuật toán KMP ở chƣơng tiếp theo. Các thuật toán chính đã đƣợc giới thiệu, trong đó có các bài toán sử dụng may rủi. Lớp bài toán may rủi có ý nghĩa lớn trong thực tế.
Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/
CHƢƠNG 2. THUẬT TOÁN SO KHỚP CHUỖI KNUTH-MORRIS-PRATT
2.1. Thuật toán KMP
2.1.1. Giới thiệu thuật toán
Thuật toán đƣợc phát minh năm 1977 bởi hai giáo sƣ của đại học Stanford, Hoa Kỳ (một trong số ít các trƣờng đại học xếp hàng số một về khoa học máy tính trên thế giới cùng với MIT, CMU cũng của Hoa Kỳ và Cambridge của Anh) Donal Knuth và Vaughan Ronald Pratt, Knuth (giải Turing năm 1971) . Thuật toán này còn có tên là KMP lấy tên viết tắt của ba ngƣời phát minh ra nó, chữ “M” là chỉ giáo sƣ J.H.Morris, một ngƣời cũng rất nổi tiếng trong khoa học máy tính.
Ý tƣởng chính của phƣơng pháp này nhƣ sau: trong quá trình tìm kiếm vị trí của mẫu P trong xâu gốc T, nếu tìm thấy một vị trí sai ta chuyển sang vị trí tìm kiếm tiếp theo và quá trình tìm kiếm sau này sẽ đƣợc tận dụng thông tin từ quá trình tìm kiếm trƣớc để không phải xét các trƣờng hợp không cần thiết [8].
Ví dụ: tìm mẫu w = “ABCDABD” trong xâu T = “ABC ABCDAB ABCDABCDABDE”. Ở mỗi thời điểm, thuật toán luôn đƣợc xác định bằng hai biến kiểu nguyên, m và i, đƣợc định nghĩa lần lƣợt là vị trí tƣơng ứng trên S bắt đầu cho một phép so sánh với W, và chỉ số trên W xác định kí tự đang đƣợc so sánh. Khi bắt đầu, thuật toán đƣợc xác định nhƣ sau:
m: 0
S: ABC ABCDAB ABCDABCDABDE W: ABCDABD
i: 0
Chúng ta tiến hành so sánh các kí tự của W tƣơng ứng với các kí tự của S, di chuyển lần lƣợt sang các chữ cái tiếp theo nếu chúng giống nhau. S[0] và W[0] đều là „A‟. Ta tăng i:
Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/ m: 0
S: ABC ABCDAB ABCDABCDABDE W: ABCDABD
i: _1
S[1] và W[1] đều là „B‟. Ta tiếp tục tăng i:
m: 0
S: ABC ABCDAB ABCDABCDABDE W: ABCDABD
i: __2
S[2] và W[2] đều là „C‟. Ta tăng i lên 3:
m: 0
S: ABC ABCDAB ABCDABCDABDE W: ABCDABD
i: ___3
Nhƣng, trong bƣớc thứ tƣ, ta thấy S[3] là một khoảng trống trong khi W[3] = 'D', không phù hợp. Thay vì tiếp tục so sánh lại ở vị trí S[1], ta nhận thấy rằng không có kí tự 'A' xuất hiện trong khoảng từ vị trí 0 đến vị trí 3 trên xâu S ngoài trừ vị trí 0; do đó, nhờ vào quá trình so sánh các kí tự trƣớc đó, chúng ta thấy rằng không có khả năng tìm thấy xâu dù có so sánh lại. Vì vậy, chúng ta di chuyển đến kí tự tiếp theo, gán m = 4 và i = 0.
m: ____4
S: ABC ABCDAB ABCDABCDABDE W: ABCDABD
i: 0
Tiếp tục quá trình so sánh nhƣ trên, ta xác định đƣợc xâu chung "ABCDAB", với W[6] (S[10]), ta lại thấy không phù hợp. Nhƣng từ kết quả của quá trình so sánh trƣớc, ta đã duyệt qua "AB", có khả năng sẽ là khởi đầu cho
Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/
một đoạn xâu khớp, vì vậy ta bắt đầu so sánh từ vị trí này. Nhƣ chúng ta đã thấy các kí tự này đã trùng khớp với nhau kí tự trong phép so khớp trƣớc, chúng ta không cần kiểm tra lại chúng một lần nữa; ta bắt đầu với m = 8, i = 2 và tiếp tục quá trình so khớp.
m: ________8
S: ABC ABCDAB ABCDABCDABDE W: ABCDABD
i: __2
Quá trình so khớp ngay lập tức thất bại, nhƣng trong W không xuất hiện kí tự „ „,vì vậy, ta tăng m lên 11, và gán i = 0.
m: ___________11
S: ABC ABCDAB ABCDABCDABDE W: ABCDABD
i: 0
Một lần nữa, hai xâu trùng khớp đoạn kí tự "ABCDAB" nhƣng ở kí tự tiếp theo, 'C', không trùng với 'D' trong W. Giống nhƣ trƣớc, ta gán m = 15, và gán i = 2, và tiếp tục so sánh.
m: _______________15
S: ABC ABCDAB ABCDABCDABDE W: ABCDABD i: __2
Lần này, chúng ta đã tìm đƣợc khớp tƣơng ứngvới vị trí bắt đầu là S[15]. Bảng so khớp một phần T giúp ta xác định đƣợc vị trí tiếp theo để so khớp khi phép so khớp trƣớc đã thất bại. Mảng T đƣợc tổ chức để nếu chúng ta có một phép so khớp bắt đầu từ S[m] thất bại khi so sánh S[m + i] với W[i], thì vị trí của phép so khớp tiếp theo có chỉ số là m + i - T[i] trong S (T[i] là đại lƣợng xác định số ô cần lùi khi có một phép so khớp thất bại). Mặc dù phép so khớp tiếp theo sẽ bắt đầu ở chỉ số m + i - T[i], giống nhƣ ví dụ ở trên, chúng ta không cần
Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/
so sánh các kí tự T[i] sau nó, vì vậy chúng ta chỉ cần tiếp tục so sánh từ kí tự W[T[i]]. Ta có T[0] = -1, cho thấy rằng nếu W[0] không khớp, ta không phải lùi lại mà tiếp tục phép so sánh mới ở kí tự tiếp theo. Sau đây là đoạn mã giả mẫu của thuật toán tìm kiếm KMP.
algorithm kmp_search: input:
mảng kí tự, S (đoạn văn bản) mảng kí tự, W (xâu đang tìm) output:
một biến kiểu nguyên (vị trí (bắt đầu từ 0) trên S mà W được tìm thấy) define variables:
biến nguyên, m ← 0 biến nguyên, i ← 0 mảng nguyên, T
while m + i nhỏ hơn độ dài của sâu S, do: if W[i] = S[m + i], let i ← i + 1 if i bằng độ dài W, return m otherwise, if T[i] > -1,
let i ← T[i], m ← m + i - T[i] else
let i ← 0, m ← m + 1 return độ dài của đoạn văn bản S
Với sự xuất hiện của mảng T, phần tìm kiếm của thuật toán Knuth– Morris–Pratt có độ phức tạp O(k), trong đó k là độ dài của xâu S. Ngoại trừ các thủ tục nhập xuất hàm ban đầu, tất cả các phép toán đều đƣợc thực hiên trong vòng lặp while, chúng ta sẽ tính số câu lệnh đƣợc thực hiện trong vòng lặp; để làm đƣợc việc này ta cần phải tìm hiểu về bản chất của mảng T. Theo định nghĩa, mảng đƣợc tạo để: nếu một phép so khớp bắt đầu ở vị trí S[m] thất bại khi
Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/
so sánh S[m + i] với W[i], thì phép so khớp có thể thành công tiếp theo sẽ bắt đầu ở vị trí S[m + (i - T[i])]. Cụ thể hơn, phép so khớp tiếp theo sẽ bắt đầu tại vị trí có chỉ số cao hơn m, vì vậy T[i] < i.
Từ điều này, ta thấy rằng vòng lặp có thế thức hiện 2k lần. Với mỗi lần lặp, nó thực hiện một trong hai nhánh của vòng lặp. Nhánh thứ nhất tăng i và không thay đổi m, vì vậy chỉ số m + i của kí tự đang so sánh trên S tăng lên. Nhánh thứ hai cộng thêm i - T[i] vào m, và nhƣ chúng ta đã biết, đây luôn là số dƣơng. Vì vậy, vị trí m, vị trí bắt đầu của một phép so khớp tiềm năng tăng lên. Vòng lặp dừng nếu m + i = k; vì vậy mỗi nhánh của vòng lặp có thể đƣợc sử dụng trong tối đa k lần, do chúng lần lƣợt tăng giá trị của m + i hoặc m, và m ≤ m + i: nếu m = k, thì m + i ≥ k, vì vậy: do các phép toán chủ yếu tăng theo đơn