Thuật toán Brute-Forcea Trình bày thuật toán Nếu các ký tự không khớp, chúng ta di chuyển sang phần tử tiếp theo trong chuỗi và tiếp tục quá trình so sánh Quá trình trên được lặp lại c
Trang 1HỌC VIỆN CÔNG NGHỆ BƯU CHÍNH VIỄN THÔNG
BÁO CÁO CHUYÊN ĐỀ CÔNG NGHỆ PHẦN MỀM
CÁC THUẬT TOÁN ĐỐI SÁNH MẪU
(PATTERN MATCHING ALGORITHMS)
Sinh viên thực hiện: Nguyễn Quang Chí
Hà Nội, 5/2023
Trang 2Mục lục
1 Tìm kiếm mẫu từ trái sang phải 1
1.1 Thuật toán Brute - Force 2
1.2 Thuật toán Karp - Rabin 3
1.3 Thuật toán Morris - Pratt 5
1.4 Thuật toán Knuth Morris - Pratt 8
1.5 Thuật toán Not So Naive 10
2 Tìm kiếm mẫu từ phải sang trái 11
2.1 Thuật toán Tuned Boyer - Moore 11
2.2 Thuật toán Quick Search 13
3 Tìm kiếm mẫu từ vị trí cụ thể 15
3.1 Thuật toán Colussi 15
3.2 Thuật toán Skip Search 20
4 Tìm kiếm mẫu từ vị trí bất kỳ 23
4.1 Thuật toán Raita 23
Trang 31 Tìm kiếm mẫu từ trái sang phải:
1.1 Thuật toán Brute-Force
a) Trình bày thuật toán
Đặc điểm:
Không có pha tiền xử lý
Sử dụng không gian nhớ phụ hằng số
Quá trình so sánh thực hiện theo bất kỳ thứ tự nào
Độ phức tạp thuật toán là O(m*n)
Thuật toán thực hiện việc so sánh từng ký tự của mẫu với các ký tự tương ứng trong chuỗi, một cách tuần tự từ đầu đến cuối:
Đầu tiên, chúng ta xác định mẫu cần tìm trong chuỗi văn bản Gọi m
là độ dài của mẫu và n là độ dài của chuỗi văn bản
Bắt đầu từ vị trí đầu tiên của chuỗi văn bản, chúng ta so sánh mỗi ký
tự của mẫu với ký tự tương ứng trong chuỗi
Nếu tất cả các ký tự khớp, chúng ta đã tìm thấy một sự khớp hoàn hảo của mẫu trong chuỗi Chúng ta có thể trả về vị trí đầu tiên của chuỗi khớp này
Nếu các ký tự không khớp, chúng ta di chuyển sang phần tử tiếp theo trong chuỗi và tiếp tục quá trình so sánh
Quá trình trên được lặp lại cho đến khi chúng ta tìm thấy chuỗi khớphoặc đã duyệt qua toàn bộ chuỗi mà không tìm thấy
Nếu chúng ta không tìm thấy chuỗi khớp, chúng ta kết luận rằng mẫu không tồn tại trong chuỗi văn bản
b) Độ phức tạp thuật toán
Độ phức tạp của thuật toán Brute-Force làO(m*n), trong đó m là độ dài của mẫu và n là độ dài của chuỗi văn bản
Trong trường hợp tốt nhất, khi mẫu không tồn tại trong chuỗi, thuật toán
sẽ duyệt qua toàn bộ chuỗi văn bản một lần, do đó độ phức tạp là O(n)
Trong trường hợp xấu nhất, khi mỗi ký tự trong mẫu đều khớp với ký tự tương ứng trong chuỗi, hoặc khi chuỗi và mẫu có độ dài gần bằng nhau, thuật toán sẽ thực hiện m*n lần so sánh, do đó độ phức tạp là O(m*n) c) Kiểm nghiệm thuật toán
Vậy ta thấy chỉ có một lần tìm thấy x trong mảng y
Trong ví dụ trên, thuật toán Brute - Force phải thực hiện 7 lần so sánh
Trang 4d) Lập trình theo thuật toán
1.2 Thuật toán Karp-Rabin
a) Trình bày thuật toán
Đặc điểm:
Sử dụng hàm băm
Giai đoạn tiền xử lý có độ phức tạp là O(m)
Giai đoạn tìm kiếm có độ phức tạp là O(m + n)
Thuật toán dựa trên việc sử dụng hàm băm để so sánh các cặp chuỗi ký
tự liên tiếp của văn bản với mẫu Dưới đây là cách thuật toán hoạt động
Chuẩn bị:
Xác định một hàm băm để ánh xạ các xâu con sang các giá trị hash Hàm băm cần được thiết kế sao cho hai xâu con giống nhau có khả năng tạo ra cùng một giá trị hash
Tính toán giá trị hash của mẫu
Tiến hành tìm kiếm trong văn bản:
Tính toán giá trị hash của chuỗi ban đầu của văn bản có cùng độdài với mẫu
So sánh giá trị hash của cửa sổ văn bản với giá trị hash của mẫu
Nếu giá trị hash khớp, kiểm tra thực sự xem hai chuỗi có khớp hoàn toàn hay không
Nếu khớp, ta đã tìm thấy một khớp hoàn chỉnh và có thể xử lý kết quả tìm kiếm ở đây
Nếu không khớp, tiếp tục dịch cửa sổ sang phải và tính lại hash bằng cách loại bỏ ký tự đầu tiên và thêm ký tự mới
Trang 5b) Độ phức tạp thuật toán
Độ phức tạp của thuật toán này là O(n + m), trong trường hợp tốt nhất vàtrung bình
Tuy nhiên, trong trường hợp xấu nhất, khi xảy ra nhiều xung đột hash,
độ phức tạp thời gian có thể lên đến O(n * m), đó là trường hợp hash giống nhau nhưng các ký tự không khớp và chúng ta phải thực kiểm tra chi tiết để xác định sự khớp hoàn chỉnh
c) Kiểm nghiệm thuật toán
Kiểm nghiệm tiền xử lý
Trang 6d) Lập trình theo thuật toán
1.3 Thuật toán Morris-Pratt
a) Trình bày thuật toán
Đặc điểm:
Thực hiện từ trái sang phải
Giai đoạn tiền xử lý có độ phức tạp là O(m)
Pha tìm kiếm có độ phức tạp O(n + m)
Thực hiện tối đa 2n - 1 các so sánh ký tự trong văn bản
Độ trễ bị bao bọc bởi m
Thuật toán sử dụng bảng longest proper prefix để tối ưu hóa việc di chuyển của mẫu trong quá trình tìm kiếm Dưới đây là cách hoạt động:
Xây dựng bảng LPS:
Bắt đầu bằng việc khởi tạo một mảng nextMp với độ dài bằng
độ dài của mẫu với giá trị đầu tiên bằng -1
Duyệt qua mẫu từ trái sang phải và xác định độ dài lớn nhất của proper prefix mà cũng là proper suffix cho mỗi vị trí
Trang 7 Tiến hành tìm kiếm trong văn bản:
Duyệt qua văn bản từ trái sang phải và so sánh ký tự của văn bản với ký tự của mẫu
Nếu không khớp, sử dụng bảng LPS để di chuyển đến vị trí tiếp theo cần so sánh
Nếu khớp, tiếp tục duyệt đến khi tìm thấy một chuỗi khớp hoàn chỉnh
Thuật toán tiếp tục cho đến khi duyệt qua toàn bộ văn bản hoặc tìm thấy tất cả các chuỗi khớp của mẫu trong văn bản
b) Độ phức tạp thuật toán
Độ phức tạp của thuật toán là O(n + m) trong trường hợp tốt nhất và trung bình
c) Kiểm nghiệm thuật toán
Kiểm nghiệm tiền xử lý preMp(x, m, mpNext)
Vậy ta thấy chỉ có 1 lần duy nhất tìm thấy x trong y tại i = 3, j = 6
d) Lập trình theo thuật toán
Trang 81.4 Thuật toán Knuth Morris-Pratt
Trang 9a) Trình bày thuật toán
Đặc điểm:
Thực hiện từ trái sang phải
Có pha tiền xử lý với độ phức tạp O(m)
Độ phức tạp thuật toán là O(n + m)
Thuật toán với bước tiền xử lý xây dựng bảng phụ với mẫu để khi vị trí hiện tại không khớp ta biết được vị trí tiếp theo cần được so sánh
Tiếp theo tiến hành tìm kiếm trong văn bản:
Khởi tạo biến i = 0 để chỉ định vị trí trong mẫu
Khởi tạo biến j = 0 để chỉ định vị trí trong văn bản
Trong khi j < độ dài văn bản:
Nếu ký tự mẫu tại vị trí i và ký tự mẫu tại vị trí j khớp nhau, tăng i và j lên 1
Nếu i bằng độ dài mẫu, tức là chúng ta đã tìm thấy một chuỗi khớp hoàn chỉnh
Nếu i khác 0 và ký tự mẫu tại vị trí i và ký tự văn bản tại vị trí j không khớp nhau, ta cần di chuyển i đến vị trí được xác định bởi bảng phụ
Nếu i bằng 0, ta tăng j lên 1b) Độ phức tạp thuật toán
Trong quá trình tiền xử lý, việc xây dựng bảng phụ có độ phức tạp thời gian O(m)
Trong quá trình tìm kiếm, chúng ta duyệt toàn bộ văn bản và so sánh từng ký tự của văn bản với mẫu Vì chúng ta chỉ duyệt qua mỗi vị trí trong văn bản và mẫu một lần, nên thời gian tìm kiếm là O(n) Tại mỗi vịtrí, chúng ta thực hiện một số so sánh ký tự nhưng không vượt quá độ dàicủa mẫu, do đó có thể xem như là O(m)
Vì vậy, tổng thời gian thực hiện của thuật toán là O(n + m)
c) Kiểm nghiệm thuật toán
Kiểm nghiệm pha tiền xử lý preKmp(x, m, kmpNext)
Trang 111.5 Thuật toán Not So Naive
a) Trình bày thuật toán
Trong pha tìm kiếm của thuật toán Not So Naive, việc so sánh các ký tự mẫu x được thực hiện theo thứ tự: 1, 2,…, m - 2, m - 1, 0
Mỗi lần thử (tức mỗi lần đặt cửa sổ vào đoạn y[j j + m - 1] của văn bản y): nếu x[0] = x[1] và x[1] ≠ y[j + 1] hoặc nếu x[0] ≠ x[1] và x[1] = y[j+1] mẫu được dịch chuyển 2 vị trí, ngược lại thì dịch 1
b) Độ phức tạp thuật toán
Pha tiền xử lý: độ phức tạp hằng số
Pha tìm kiếm: O(n * m)
c) Kiểm nghiệm thuật toán
Kiểm nghiệm tiền xử lý:
(x[1] != y[12]):No memcmp(x + 2, y + 13, 2):Yes (x[0] == y[12]):No 12
Vậy ta thấy chỉ có 1 lần tìm thấy x trong y bắt đầu tại j = 2
Trang 12d) Lập trình theo thuật toán
2 Thuật toán tìm kiếm mẫu từ phải sang trái
2.1 Thuật toán Tuned Boyer-Moore
a) Trình bày thuật toán
Thuật toán sử dụng bad-character shift để tìm ký tự x[m - 1] trong y Thuật toán yêu cầu lưu giá trị của bmBc[x[m - 1]] vào biến shift, và sau
đó đặt lại bmBc[x[m - 1]] = 0 khi x[m - 1] được tìm thấy trong y, m - 1
ký tự còn lại được kiểm tra và sau đó dịch cửa sổ một đoạn shift
Trang 13c) Kiểm nghiệm thuật toán
Kiểm nghiệm tiền xử lý preBc(x, m, bc)
Vậy ta thấy chỉ có 1 lần tìm được x trong y tại j = 5
d) Lập trình theo thuật toán
Trang 142.2 Thuật toán Quick Search
a) Trình bày thuật toán
Pha tìm kiếm có độ phức tạp là O(m * n)
Rất nhanh trong thực tế với những mẫu ngắn và dãy ký tự alpha lớn
Trang 15 Thuật toán Quick Search hoạt động bằng cách sử dụng một bảng tần suất
để xác định số bước dịch chuyển tối ưu khi một ký tự không khớp xảy
ra Dưới đây là cách hoạt động:
Chuẩn bị dữ liệu: Xây dựng bảng tần suất để lưu trữ số bước dịch chuyển tối ưu cho mỗi ký tự trong mẫu
Với các ký tự có trong mẫu, số bước dịch chuyển tối ưu là độ dài của mẫu trừ đi chỉ số xuất hiện cuối cùng của ký tự đó trong mẫu
Với các ký tự không có trong mẫu, số bước dịch chuyển tối ưu
là độ dài của mẫu
Tiến hành tìm kiếm trong văn bản:
Khởi tạo biến j để chỉ định vị trí ban đầu của mẫu trong văn bản
Kiểm tra xem mẫu có khớp với văn bản từ vị trí j không
Nếu mẫu khớp hoàn toàn, tức là chúng ta tìm được một khớp hoàn chỉnh và có thể xử lý kết quả tìm kiếm ở đây
Nếu ký tự cuối cùng của mẫu không khớp với ký tự tại vị trí j,
sử dụng bảng tần suất để xác định số bước dịch chuyển tối ưu
Tiếp tục lặp lại cho đến khi vị trí j vượt qua độ dài của văn bản hoặc tìm thấy tất cả các khớp của mẫu trong văn bản
Kiểm nghiệm tiền xử lý preQsBc(x, m, qsBc)
Trang 16d) Lập trình theo thuật toán
3 Thuật toán tìm kiếm mẫu từ vị trí cụ thể
3.1 Thuật toán Colussi
a) Trình bày thuật toán
Đặc điểm:
Là thuật toán cải tiến từ thuật toán Knuth Morris-Pratt
Mẫu tìm kiếm sẽ được chia thành 2 tập con Tập thứ nhất sẽ được duyệt từ trái sang phải khi gặp mismatch ta duyệt tập thứ hai từ phải sang trái
Pha tiền xử lý có độ phức tạp là O(m)
Pha tìm kiếm có độ phức tạp là O(n)
Trong trường hợp xấu nhất quá trình thực thi sẽ mất 3n/2 lần so sánh
ký tự
Trang 17 Thuật toán Colussi được thiết kế dựa theo những phân tích từ thuật toán Knuth Morris-Pratt, các ký tự trong mẫu được chia thành 2 tập riêng biệt,mỗi phép thử bao gồm 2 pha:
Pha thứ nhất thực hiện so sánh từ trái sang phải lần lượt các ký tự tạinhững vị trí kmpNext > -1 Những vị trí này gọi là noholes
Pha thứ hai so sánh ký tự từ phải sang trái lần lượt các ký tự tại những vị trí kmpNext = -1 và gọi là holes
Chiến lược này có 2 ưu điểm:
Khi gặp mismatch trong pha thứ nhất, sau khi thực hiện bước dịch takhông cần phải so sánh lại các ký tự tại những vị trí noholes phía trước
Khi gặp mismatch trong pha thứ hai có nghĩa là có một đoạn suffix của mẫu đã match với một đoạn của văn bản Sau khi dịch chuyển cửa sổ thích hợp, một prefix của mẫu sẽ match với một yếu tố của văn bản, sau đó không cần thiết phải so sánh yếu tố này lại
b) Độ phức tạp thuật toán
Độ phức tạp của pha tiền xử lý là O(m)
Độ phức tạp của pha tìm kiếm là O(n)
c) Kiểm nghiệm thuật toán
Kiểm nghiệm pha tiền xử lý preColussi(x, m, h, next, shift)
Trang 18( i >= 8 || last >= j + h[i] ): No
Trang 19Ta thấy thuật toán Colussi thực hiện 20 phép so sánh trong ví dụ trên
Trang 20d) Lập trình theo thuật toán
Trang 213.2 Thuật toán Skip Search
a) Trình bày thuật toán
Trang 22 Với mỗi ký tự trong bảng chữ cái, một thùng chứa (bucket) sẽ chứa tất cảcác vị trí xuất hiện của ký tự đó trong xâu mẫu x Khi một ký tự xuất hiện k lần trong mẫu, bucket sẽ lưu k vị trí của ký tự đó Khi mà xâu y chứa ít ký tự hơn trong bảng chữ cái thì sẽ có nhiều bucket rỗng
Quá trình xử lý của thuật toán Skip Search bao gồm việc tính các bucket cho tất cả các ký tự trong bảng chữ cái Đối với mỗi ký tự c thuộc bảng chữ cái, ta có:
z[c] = {i: 0 ≤ i ≤ m – 1 và x[i] = c} z[c] chính là bucket của ký tự c
Vòng lặp chính của pha tìm kiếm sẽ kiểm tra mọi ký tự thứ m, y[j] (Do
đó sẽ có n/m lần lặp) Đối với mỗi y[j], nó sử dụng mỗi vị trí trong bucket z[y[j]] để kiểm tra xem liệu tại mỗi vị trí trong z[y[j]] thì có tìm đƣợc một x trong y không Nó thực hiện so sánh x với y từ vị trí đầu tiên, lần lƣợt từng ký tự một cho đến khi gặp một sự không khớp hoặc tất cả đều khớp
b) Độ phức tạp thuật toán
Độ phức tạp thuật toán là O(n * m) trong trường hợp tệ nhất khi mẫu và văn bản có cấu trúc gần như giống nhau và tất cả các vị trí trong văn bản đều phải được kiểm tra
Còn trong trường hợp tốt nhất hoặc trung bình độ phức tạp thuật toán là O(n / m)
c) Kiểm nghiệm thuật toán
Trang 23 Kiểm nghiệm pha tìm kiếm
Ta thấy thuật toán Skip Search thực hiện 14 phép so sánh trong ví dụ trên
Trang 24d) Lập trình theo thuật toán
4 Thuật toán tìm kiếm mẫu từ vị trí bất kỳ
4.1 Thuật toán Raita
a) Trình bày thuật toán
Đầu tiên so sánh ký tự cuối của mẫu với ký tự cuối của cửa sổ, nếu khớp tiếp tục so sánh ký tự đầu tiên của mẫu và ký tự đầu tiên của cửa sổ, nếu khớp tiếp tục so sánh ký tự giữa của mẫu với ký tự giữa của cửa sổ Nếu vẫn khớp mới so sánh các ký tự còn lại, bắt đầu tự ký tự thứ 2
b) Độ phức tạp thuật toán
Pha tiền xử lý: độ phức tạp thời gian là O(m + ∂) và độ phức tạp bộ nhớ
là O(∂)
Pha tìm kiếm có độ phức tạp thời gian là O( m* n)
c) Kiểm nghiệm thuật toán
Trang 26Ta thấy thuật toán Raita thực hiện 18 phép so sánh trong ví dụ trên
Và chỉ tìm thấy x trong y tại vị trí j = 5
Trang 27d) Lập trình theo thuật toán