×

Cài đặt thuật toán Aho-Corasick trong lập trình

Aho-Corasick là một thuật toán nổi tiếng dùng để tìm kiếm các chuỗi (pattern) trong một văn bản lớn. Nó đặc biệt hiệu quả khi chúng ta cần tìm nhiều chuỗi cùng lúc. Được sáng tạo bởi Alfred V. Aho và Margaret J. Corasick vào năm 1975, thuật toán này kết hợp giữa cơ chế của Trie và thuật toán Knuth-Morris-Pratt (KMP).

Để dễ hiểu, chúng ta sẽ khám phá qua từng bước để cài đặt thuật toán Aho-Corasick trong lập trình:

Bước 1: Xây dựng cấu trúc Trie cho các chuỗi cần tìm

Trước tiên, xây dựng một cấu trúc Trie, trong đó mỗi nút đại diện cho một ký tự và từ root, chúng ta có thể truy vết từng ký tự trong các chuỗi cần tìm.

class TrieNode:
    def __init__(self):
        self.children = {}
        self.fail_link = None
        self.output = []

Bước 2: Thêm các chuỗi vào Trie

Chúng ta cần một hàm để thêm từng chuỗi vào trong cấu trúc Trie. Mỗi khi một chuỗi được thêm vào, nút cuối của chuỗi đó sẽ chứa một chỉ số hoặc nhãn tương ứng cho chuỗi đó.

def add_pattern_to_trie(trie, pattern, index):
    node = trie
    for char in pattern:
        if char not in node.children:
            node.children[char] = TrieNode()
        node = node.children[char]
    node.output.append(index)

Bước 3: Tạo các liên kết thất bại (Failure Links)

Liên kết thất bại giúp thuật toán có thể quay lại đúng vị trí khi đối mặt với một ký tự không khớp. Để tạo các liên kết này, ta sử dụng cơ chế duyệt theo chiều rộng (BFS).

from collections import deque

def create_failure_links(trie):
    queue = deque()
    for child in trie.children.values():
        child.fail_link = trie
        queue.append(child)
    
    while queue:
        current_node = queue.popleft()
        
        for key, child_node in current_node.children.items():
            fail_state = current_node.fail_link
            while fail_state is not None and key not in fail_state.children:
                fail_state = fail_state.fail_link
            
            if fail_state:
                child_node.fail_link = fail_state.children[key]
            else:
                child_node.fail_link = trie
            
            child_node.output += child_node.fail_link.output
            queue.append(child_node)

Bước 4: Tìm kiếm chuỗi trong văn bản

Sau khi cấu trúc Trie và liên kết thất bại đã được tạo, chúng ta có thể sử dụng thuật toán này để tìm kiếm chuỗi cần tìm trong một văn bản cụ thể.

def search_in_text(trie, text):
    node = trie
    results = []

    for i, char in enumerate(text):
        while node is not None and char not in node.children:
            node = node.fail_link
        
        if node is None:
            node = trie
            continue
        
        node = node.children[char]
        for pattern_index in node.output:
            results.append((pattern_index, i))

    return results

Kết Luận

Cài đặt thuật toán Aho-Corasick đòi hỏi sự hiểu biết về cấu trúc dữ liệu Trie và cơ chế liên kết thất bại. Lợi thế lớn nhất của Aho-Corasick là hiệu suất tìm kiếm nhanh chóng và hiệu quả, đặc biệt là khi cần tìm nhiều chuỗi trong một văn bản lớn. Điều này rất hữu ích trong các ứng dụng xử lý ngôn ngữ tự nhiên, antivirus detection, và nhiều lĩnh vực khác.

Qua ví dụ bằng Python bên trên, hy vọng bạn đã có cái nhìn tổng quan và hiểu rõ hơn về cách cài đặt và sử dụng thuật toán Aho-Corasick trong lập trình.

Comments