1. Trang chủ
  2. » Luận Văn - Báo Cáo

Tìm hiểu thuật toán so khớp xâu kí tự

8 1,4K 19

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 8
Dung lượng 66,09 KB

Nội dung

1. Mở đầuTrong ngành Khoa học máy tính, các thuật toán so khớp xâu kí tự (hay còn gọi là thuậttoán tìm kiếm chuỗi) là một trong những bài toán cơ bản và quan trọng nhất. Mục đíchcủa thuật toán là tìm kiếm vị trí của các chuỗi con (còn được gọi là các pattern) trongmột chuỗi kí tự hoặc một văn bản lớn. Bài toán này có tính ứng dụng quan trọng trênthực tế. Chẳng hạn như bài toán Tìm các pattern trong các chuỗiDNA là bài toán cơbản đối với ngành Tin sinh học. Các phần mềm diệt virus hiện đại có chứa hàng chụctriệu các pattern là các “dấu hiệu” (virus signature) của các con virus mà máy tính đãbiết. Khi quét virus thì phần mềm diệt virus phải tìm kiếm các pattern này trong cácfiles hay bộ nhớ của máy…12. Thuật toán KnuthMorris Pratt2.1. Sơ lượcNếu chỉ tính các thuật toán tìm kiếm sự xuất hiện của một chuỗi đơn cho trước bêntrong một chuỗi khác thì đã có đến hàng trăm thuật toán khác nhau, đã được thống kêở tài liệu tham khảo 2. Thuật toán KnuthMorris Pratt (KMP) là một trong số hàngtrăm thuật toán đó.Thuật toán KMP được tìm ra bởi hai nhà Khoa học máy tính, Giáo sư danh dự của Đạihọc Stanford là Donald Ervin Knuth và Vaughan Ronald Pratt cùng với Giáo sưngười Mĩ James Hiram Morris vào năm 1974, họ nghiên cứu độc lập với nhau, tuynhiên, sau đó cả ba người đã cùng công bố thuật toán này vào năm 1977. 3Ý tưởng của thuật toán KMP đơn giản là tìm kiếm sự xuất hiện của một “từ” W trongmột “xâu văn bản” S bằng cách tiếp tục quá trình tìm kiếm khi không phù hợp, chínhtừ cho ta đầy đủ thông tin để xác định vị trí bắt đầu của kí tự so sánh tiếp theo, do đóbỏ qua quá trình kiểm tra lại các kí tự đã so sánh trước đó.

Trang 1

Tìm hiểu thuật toán so khớp xâu kí tự (string matching)

Nguyễn Thành Đạt, Ngô Văn Dũng – K59B – Khoa Công nghệ Thông tin – Đại học

Sư phạm Hà Nội Hướng dẫn: TS Phạm Đức Đông – Khoa Toán tin – Đại học Sư phạm Hà Nội

Tóm tắt: Đề tài bài tập lớn môn học này đã trình bày những tìm hiểu về cách thức

hoạt động của hai trong số nhiều thuật toán so khớp xâu kí tự (string searching algorithm/ string matching algorithm) là thuật toán Knuth-Morris-Pratt (KMP) và thuật toán Rabin-Karp Bên cạnh đó là việc đánh giá độ phức tạp của hai thuật toán, so sánh tính khả dụng của chúng với các thuật toán khác để giải những bài toán tương tự với những trường hợp cụ thể, cũng như cài đặt chương trình mô phỏng các thuật toán bằng ngôn ngữ lập trình C++

1. Mở đầu

Trong ngành Khoa học máy tính, các thuật toán so khớp xâu kí tự (hay còn gọi là thuật toán tìm kiếm chuỗi) là một trong những bài toán cơ bản và quan trọng nhất Mục đích

của thuật toán là tìm kiếm vị trí của các chuỗi con (còn được gọi là các pattern) trong

một chuỗi kí tự hoặc một văn bản lớn Bài toán này có tính ứng dụng quan trọng trên

thực tế Chẳng hạn như bài toán Tìm các pattern trong các chuỗi-DNA là bài toán cơ

bản đối với ngành Tin sinh học Các phần mềm diệt virus hiện đại có chứa hàng chục triệu các pattern là các “dấu hiệu” (virus signature) của các con virus mà máy tính đã biết Khi quét virus thì phần mềm diệt virus phải tìm kiếm các pattern này trong các files hay bộ nhớ của máy…[1]

2. Thuật toán Knuth-Morris-Pratt

2.1. Sơ lược

Nếu chỉ tính các thuật toán tìm kiếm sự xuất hiện của một chuỗi đơn cho trước bên trong một chuỗi khác thì đã có đến hàng trăm thuật toán khác nhau, đã được thống kê

ở tài liệu tham khảo [2] Thuật toán Knuth-Morris-Pratt (KMP) là một trong số hàng trăm thuật toán đó

Thuật toán KMP được tìm ra bởi hai nhà Khoa học máy tính, Giáo sư danh dự của Đại

học Stanford là Donald Ervin Knuth và Vaughan Ronald Pratt cùng với Giáo sư người Mĩ James Hiram Morris vào năm 1974, họ nghiên cứu độc lập với nhau, tuy

nhiên, sau đó cả ba người đã cùng công bố thuật toán này vào năm 1977 [3]

Ý tưởng của thuật toán KMP đơn giản là tìm kiếm sự xuất hiện của một “từ” W trong một “xâu văn bản” S bằng cách tiếp tục quá trình tìm kiếm khi không phù hợp, chính

từ cho ta đầy đủ thông tin để xác định vị trí bắt đầu của kí tự so sánh tiếp theo, do đó

bỏ qua quá trình kiểm tra lại các kí tự đã so sánh trước đó

2.2. Hoạt động của thuật toán

Trang 2

Bài toán

Input: Xâu văn bản S và một chuỗi W

Output: Vị trí của chuỗi W trong xâu văn bản S

Ý tưởng

Giả sử cho xâu văn bản S: CCABCABCABCABCD

Tìm chuỗi W: ABCABCD trong xâu văn bản S

Ta đưa thêm vào hai biến m và i Trong đó: m là vị trí tương ứng trên xâu S bắt đầu cho một phép so sánh với W và i là chỉ số chỉ số trên w xác định kí tự đang được so sánh

m 0

W ABCABCD

Bắt đầu so sánh các kí tự tương ứng của S và W

S[0] =”C” ≠ W[0] =”A” → m++

m 1

W _ABCABCD

i _0

S[1] =”C” ≠ W[0] =”A” → m++

m 2

W ABCABCD

i 0

S[2] = W[0] =”A” → i++

S[3] = W[1] =”B” → i++

S[4] = W[2] =”C” → i++

S[5] = W[3] =”A” → i++

S[6] = W[4] =”B” → i++

m 2

W ABCABCD

i 5

S[7] = W[5] =”C” → i++

m 2

Trang 3

W ABCABCD

i 6

S[8] =”A” ≠ W[6] =”D”

Nhận thấy không có kí tự “D” trong 8 kí tự đầu của xâu S , tăng m lên 8 để bắt đầu xét từ đây, trả lại i=0 để xét lại từ kí tự đầu của xâu W

m _8

W _ABCABCD

I _0

S[8] = S[0] = “A” → i++

S[9] = S[1] = “B” → i++

S[10] = S[2] = “C” → i++

S[11] = S[3] = “A” → i++

S[12] = S[4] = “B” → i++

S[13] = S[5] = “C” → i++

S[14] = S[6] = “D” → i++

Vậy đã tìm ra vị trí của chuỗi W trong xâu văn bản S ở vị trí m=8

Thuật toán

Input: Xâu văn bản (S) và chuỗi con (W) cần tìm.

Output: vị trí tìm thấy W trong xâu S.

BEGIN

m = 0;

i = 0;

{MẢNG 1 CHIỀU T}; // Sử dụng hàm xây dựng bảng KMP

WHILE ((m+i)<length(S)) DO

BEGIN

IF (W[i] = S[m+i]) THEN i=i+1;

IF (i=length(W)) THEN return(m) ELSE (m=m+i+T[i]);

IF (T[i] > -1 ) THEN i = -1 ELSE i = 0;

END;

Writeln(“Không tìm ra chuỗi W trong xâu S”);

END.

Trong thuật toán trên, bước đầu tiên cần xây dựng mảng một chiều T Mảng T[i] sinh

ra để chỉ khoảng cách từ kí tự thứ i tới kí tự giống kí tự đầu tiên (với điều kiện kí tự thứ i phải giống kí tự đó) Mảng một chiều T được gọi là bảng KMP

Xây dựng bảng KMP

Input: chuỗi con W cần tìm, mảng T

Output: bảng KMP

Trang 4

Var pos, cnd: integer;

pos = 2;

cnd = 0;

T[0] = -1;

WHILE (pos < length(W)) DO

BEGIN

IF (W[pos-1] = W[cnd]) THEN

BEGIN

T[pos] = cnd + 1;

pos = pos +1;

cnd = cnd +1;

END;

ELSE IF (cnd > 0) THEN cnd = T[cnd] ELSE

BEGIN

T[pos] = 0;

pos = pos +1;

END;

END;

END.

Bảng KMP cho ví dụ trên như sau:

T[0] = -1;

Để tính T[1] cần tìm một xâu con “A” đồng thời là xâu con bắt đầu của W → T[1] = 0; Tương tự, T[2] = 0;

Tới W[3], ta thấy kí tự này trùng với kí tự bắt đầu của xâu W[0] Nhưng T[i] là độ dài xâu dài nhất trùng với xâu con bắt đầu trong W tính đến W[i-1] nên T[3] = 0 và T[4] = 1;

Tương tự, kí tự W[4] trùng với kí tự W[1] nên T[5] = 2, kí tự W[5] trùng với kí tự W[2] nên T[6] = 3

2.3. Đánh giá độ phức tạp của thuật toán

Thuật toán xây dựng bảng KMP có độ phức tạp O(n) với 1 vòng lặp while

Thuật toán chính có độ phức tạp O(k) với 1 vòng lặp while

Với trường hợp tốt nhất, chuỗi kí tự không bị lặp, độ phức tạp là O(n+k)

Trang 5

Với trường hợp xấu nhất, độ phức tạp là O(n.k), khi chuỗi có các kí tự lặp lại nhiều lần

3. Thuật toán Rabin-Karp

3.1. Sơ lược

Thuật toán Rabin-Karp được phát minh bởi nhà khoa học máy tính người Israel

Michael O.Rabin và nhà khoa học máy tính, nhà toán học lý thuyết người Mĩ Richard M.Karp vào năm 1987 [4] Thuật toán Rabin-Karp sử dụng hàm băm (hash)

để tìm kiếm một chuỗi con (pattern) trong một xâu văn bản Thuật toán sử dụng hàm băm để so sánh các giá trị băm của các chuỗi trước khi thực sự so sánh chuỗi Phương pháp này giúp tiết kiệm thời gian so sánh, đặc biệt là với các chuỗi so sánh dài

3.2. Hàm băm

3.2.1. Hàm băm cơ bản

Hàm băm là giải thuật nhằm sinh ra các giá trị băm tương ứng với mỗi khối dữ liệu, một chuỗi kí tự, một đối tượng trong lập trình hướng đối tượng, Giá trị băm đóng vai gần như một khóa để phân biệt các khối dữ liệu, tuy nhiên, người ta chấp hiện tượng trùng khóa hay còn gọi là đụng độ và cố gắng cải thiện giải thuật để giảm thiểu sự đụng độ đó Hàm băm thường được dùng trong bảng băm nhằm giảm chi phí tính toán khi tìm một khối dữ liệu trong một tập hợp, nhờ việc so sánh các giá trị băm nhanh hơn việc so sánh những khối dữ liệu có kích thước lớn [5]

Một hàm băm đơn giản nhất đó là tính toán giá trị băm dựa trên mã ASCII hoặc UNICODE của từng ký tự

Ví dụ với chuỗi nguồn “abcdefgh” và chuỗi cần tìm có độ dài 4 thì giá trị băm đầu tiên sẽ là:

h1 = a + b + c + d

= 97 + 98 + 99 + 100

= 394

Giá trị băm tiếp theo cần tính là

h2 = b + c + d + e

= h1 – a + e

= 394 – 97 + 101

= 398

Các hàm băm kiểu này có tốc độ tính toán cao, giá trị băm chỉ được tính toán lần đầu, các giá trị tiếp theo được tính từ giá trị trước đó Phép tính băm này không phụ thuộc vào số lượng kí tự cần tìm kiếm Tuy nhiên hàm băm này lại có khả năng gây trùng cao do phép tính cộng giá trị quá đơn giản Chẳng hạn với chuỗi cần tìm “bcde” thì các chuỗi “cbed”, “ccdd”, “acak”…sẽ có cùng giá trị băm

Vì vậy, một hàm băm tốt cần thỏa mãn các điều kiện sau:

- Tính toán nhanh

Trang 6

- Các khóa được phân bố đều trong bảng.

- Ít xảy ra đụng độ

- Xử lý được các loại khóa có kiểu dữ liệu khác nhau

3.2.2. Hàm băm Rolling hash

Để giảm thiểu việc trùng giá trị băm mà vẫn đảm bảo tính toán các giá trị băm nhanh dựa trên giá trị băm trước đó, hàm băm cho thuật toán Rabin-Karp sử dụng ý tưởng cơ

số Phép tính băm này gọi là Rolling hash

Ý 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]dM-1 + a[i+1]dM-2 + …+ a[i+M-1]d0

Và có thể giả sử rằng ta biết giá trị của h(x) = x mod q Nhưng dịch 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]dM-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

3.3. Phép đối sánh mẫu Rabin-Karp

FUNCTION RABINKARP: 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;

Trang 7

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;

RABINKARP:= 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 dM-1mod 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: đ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.[5]

3.4. Đánh giá độ phức tạp

Đối với xâu văn bản độ dài n và với p pattern chiều dài m, trường hợp trung bình và trường hợp tốt nhất có độ phức tạp là O(m+n) trong không gian O(p) Trường hợp tồi nhất có độ phức tạp là O(mn) [4]

Việc chuẩn bị trong thuật toán Karp-Rabin có độ phức tạp O(m) Tuy vậy thời gian tìm kiếm lại tỉ lệ với O(m*n) vì có thể có nhiều trường hợp hàm băm của chúng ta bị lừa

và không phát huy tác dụng Nhưng đó chỉ là những trường hợp đặc biệt, thời gian tính

toán của thuật toán KR trong thực tế thường tỉ lệ với O(n+m) Hơn nữa thuật toán

Rabin-Karp có thể dễ dàng mở rộng cho các mẫu, văn bản dạng 2 chiều, do đó khiến cho nó trở nên hữu ích hơn so với các thuật toán còn lại trong việc xử lý ảnh.[5]

4. Kết luận

Trang 8

Trong đề bài Bài Tập Lớn Môn Học lần này, chúng em đã tìm hiểu cách thức hoạt động cũng như cài đặt hai trong số rất nhiều thuật toán tìm kiếm xâu kí tự (string

matching) là thuật toán Knuth-Morris-Pratt và thuật toán Rabin-Karp Dù đã dành

nhiều thời gian tìm hiểu và hoàn thiện bài tập nhưng chắc chắn sẽ không tránh khỏi sai sót Chúng em mong sẽ nhận được những lời nhận xét và đóng góp ý kiến từ thầy cô cũng như các bạn để bài tập được hoàn thiện hơn Xin chân thành cảm ơn

TÀI LIỆU THAM KHẢO

[1] T.H.Cormen, C.E.Leiserson, R.L.Rivest, C.Stein; Introduction to Algorithms, Second Edition.

[2] Simone Faro, Thierry Lecroq; The Exact String Matching Problem: a Comprehensive Experimental Evaluation

%E2%80%93Pratt_algorithm

[4] http://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm

[5] Nguyễn Văn Quyết, Bài toán tìm kiếm văn bản sử dụng giải thuật di truyền, Luận

văn Thạc sĩ Công nghệ thông tin, Đại học Thái Nguyên, 2009

Ngày đăng: 14/06/2016, 22:16

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w