놀라운 알고리즘: AC Automata

텍스트에서 여러 키워드를 찾을 때 기존의 문자열 일치 알고리즘은 비효율적이고 시간이 많이 소요될 수 있습니다. 그러나 효율적인 문자열 매칭 알고리즘인 AC 오토마톤(Aho-Corasick automaton) 알고리즘은 빠르고 안정적인 솔루션을 제공합니다. 대규모 텍스트에서 여러 키워드의 발생을 빠르게 찾을 수 있는 지능형 텍스트 스캐너와 같습니다. 검색 엔진, 민감한 단어 필터링 또는 텍스트 처리 분야에서 AC automata는 중요한 역할을 합니다.

특별한 데이터 구조인 트리 트리를 구성하고 오류 포인터의 지능형 점프 메커니즘을 사용하여 AC automata는 효율적인 문자열 일치를 실현합니다. 키워드의 일치하는 위치를 빠르게 찾을 수 있을 뿐만 아니라 대규모 키워드 목록도 처리할 수 있습니다. 이 알고리즘은 검색 엔진의 키워드 검색, 민감한 단어 필터링 및 문법 분석과 같은 많은 분야에서 널리 사용됩니다.

이 기사에서는 AC automata의 원리와 주요 속성에 대해 자세히 설명합니다. Trie 트리를 구축하는 방법과 매칭 효율성을 개선하기 위해 실패 포인터를 사용하는 방법을 살펴보겠습니다. 또한 다양한 분야에서 AC 오토마타의 응용 시나리오에 대해 논의하고 독자가 이 강력한 알고리즘을 더 잘 이해하고 적용할 수 있도록 실용적인 코드 예제를 제공합니다.

AC automata는 동시에 여러 패턴 문자열을 일치시킬 수 있는 강력한 문자열 일치 알고리즘이며 대규모 텍스트를 처리할 때 효율적인 속도를 제공합니다.

AC 오토마타 알고리즘의 기본 아이디어는 각 상태가 현재 일치하는 패턴 문자열의 접두사를 나타내는 유한 상태 머신을 구축하는 것입니다. 알고리즘은 여러 패턴 문자열을 트리 형태로 구성하여 Trie 트리(키워드 트리 또는 접두사 트리라고도 함)를 구성하고 상태 전이를 위해 장애 링크(failure link)를 사용합니다.

AC 자동화에서 각 상태 노드에는 현재 노드와 유사한 가장 긴 일치 접두사를 가리키는 오류 포인터가 있습니다. 텍스트에서 일치가 실패하면 알고리즘은 실패 포인터의 안내에 따라 다음 가능한 일치 위치로 이동하여 일치 효율성을 향상시킵니다.

AC 오토마톤 알고리즘의 시간 복잡도는 O(n + m + z)이며, 여기서 n은 텍스트 길이, m은 모든 패턴 문자열의 총 길이, z는 일치하는 결과의 수입니다. AC 오토마톤은 Trie 트리와 실패 포인터의 특성을 활용하기 때문에 많은 수의 패턴 문자열의 일치 문제를 효율적으로 처리할 수 있습니다.

당신이 수업의 수석 교사이고 학생들의 작문에서 "사과", "바나나", "오렌지"와 같은 몇 가지 키워드를 찾아야 한다고 가정합니다. 효율성을 위해 AC 자동 장치를 사용하기로 결정했습니다.

먼저 AC 자동 장치를 만들어야 합니다. 키워드 목록을 테이블에 넣을 것입니다. 이것이 "키워드 테이블"입니다. 각 키워드는 테이블에 그대로 왼쪽에서 오른쪽 순서로 추가되는 행입니다. 두 키워드의 접두사가 같으면 테이블에서 같은 부분을 공유합니다. 각 키워드의 끝을 나타내기 위해 특수 토큰을 사용합니다.

다음으로 키워드 테이블의 키워드 간에 연결을 구축합니다. 이러한 연결은 다음 문자를 가리키는 화살표와 같습니다. 화살표의 경로는 텍스트에서 키워드를 일치시킬 때 이동하는 방향을 나타냅니다.

학생의 작문을 받으면 작문 처음부터 읽기 시작합니다. AC 자동 장치의 루트 노드에서 시작합니다. 키워드 테이블에서 컴포지션의 첫 번째 문자와 일치하는 키워드를 찾으면 키워드 위치로 이동하여 다음 문자를 계속 읽습니다. 일치하는 키워드가 없으면 루트 노드로 돌아가서 구성의 다음 문자를 읽습니다.

키워드 테이블에서 현재 문자와 일치하는 항목을 찾지 못한 경우 특별한 "실패 포인터"를 따라 다른 노드로 이동합니다. 이 실패 포인터는 처음부터 반복되는 비교를 피하면서 일치를 계속할 위치를 알려줍니다.

전체 작문을 읽을 때까지 이러한 방식으로 작문을 계속 진행할 것입니다. 이 과정에서 키워드 표에서 키워드 끝에 도달하면 구성에서 일치하는 키워드를 찾은 것입니다.

마지막으로 찾은 모든 일치 항목을 검토하고 시작 위치와 종료 위치를 기록합니다. 이런 식으로 구성에서 핵심 단어가 나타나는 위치를 정확히 알 수 있습니다.

AC 자동장치에 대하여:

  • AC 오토마타의 원리
    • 트리 트리 구축: AC 오토마톤은 트리 트리를 구축하여 여러 패턴 문자열을 저장하고 트리 노드 간의 관계를 사용하여 패턴 문자열의 접두사 및 일치 상태를 나타냅니다.
    • 실패 포인터: 각 상태 노드에는 현재 노드와 유사한 가장 긴 일치 접두사를 가리키는 실패 포인터가 있습니다. 매칭에 실패하면 매칭 효율을 향상시키기 위해 실패 포인터에 따라 상태 이전이 수행됩니다.
  • AC Automata의 주요 특성
    • 효율적인 매칭: AC automata는 동시에 여러 패턴 문자열을 매칭할 수 있으며 시간 복잡도는 O(n + m + z)입니다. 여기서 n은 텍스트 길이, m은 모든 패턴 문자열의 총 길이, z는 일치하는 결과의 수.
    • 실패 포인터 최적화: AC 자동 장치는 실패 포인터를 사용하여 불필요한 역추적을 피하고 일치 속도를 개선하여 다음 가능한 일치 위치로 빠르게 이동할 수 있습니다.
    • 공간 효율성: AC 자동 장치의 공간 복잡성은 상대적으로 낮고 패턴 문자열의 접두어와 몇 가지 추가 포인터 정보만 저장하면 대규모 패턴 문자열을 처리하는 시나리오에 적합합니다.
  • AC Automata의 응용 시나리오
    • 텍스트 처리: AC automata는 텍스트 검색, 키워드 필터링 및 민감한 단어 감지와 같은 작업에 널리 사용되며 여러 패턴 문자열을 빠르고 정확하게 일치시킬 수 있습니다.
    • 패턴 인식: AC automata는 패턴 인식 분야에서 중요한 응용 프로그램을 가지고 있습니다. 예를 들어 DNA 시퀀스 매칭, 이미지 인식 등과 같이 여러 패턴 문자열의 발생을 효율적으로 검색할 수 있습니다.
    • 문법 분석: AC 오토마톤은 컴파일 원리의 문법 분석 단계에서 어휘 분석기에서 생성된 토큰 스트림을 처리하고 문법에서 키워드 및 구문을 식별하는 데 사용됩니다.

파이썬 기반 AC 오토마톤

class TrieNode():
    def __init__(self):
        self.child = {}
        self.failto = None
        self.is_word = False
        '''
        下面节点值可以根据具体场景进行赋值
        '''
        self.str_ = ''
        self.num = 0

class AhoCorasickAutomation:
    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.root = TrieNode()

    def buildTrieTree(self, wordlst):
        for word in wordlst:
            cur = self.root
            for i, c in enumerate(word):
                if c not in cur.child:
                    cur.child[c] = TrieNode()
                ps = cur.str_
                cur = cur.child[c]
                cur.str_ = ps + c
            cur.is_word = True
            cur.num += 1

    def build_AC_from_Trie(self):
        queue = []
        for child in self.root.child:
            self.root.child[child].failto = self.root
            queue.append(self.root.child[child])

        while len(queue) > 0:
            cur = queue.pop(0)
            for child in cur.child.keys():
                failto = cur.failto
                while True:
                    if failto == None:
                        cur.child[child].failto = self.root
                        break
                    if child in failto.child:
                        cur.child[child].failto = failto.child[child]
                        break
                    else:
                        failto = failto.failto
                queue.append(cur.child[child])

    def ac_search(self, str_):
        cur = self.root
        result = {}
        i = 0
        n = len(str_)
        while i < n:
            c = str_[i]
            if c in cur.child:
                cur = cur.child[c]
                if cur.is_word:
                    temp = cur.str_
                    result.setdefault(temp, [])
                    result[temp].append([i - len(temp) + 1, i, cur.num])

                '''
                处理所有其他长度公共字串
                '''
                fl = cur.failto
                while fl:
                    if fl.is_word:
                        temp = fl.str_
                        result.setdefault(temp, [])
                        result[temp].append([i - len(temp) + 1, i, cur.failto.num])
                    fl = fl.failto
                i += 1

            else:
                cur = cur.failto
                if cur == None:
                    cur = self.root
                    i += 1


        return result


acTree = AhoCorasickAutomation()

acTree.buildTrieTree(['abcdef', 'abhab', 'bcd', 'cde', 'cd', 'cdfkcdf', 'cde'])
acTree.build_AC_from_Trie()
res = acTree.ac_search('bcabcdebcedfabcdefababkabhabkcdbcde')
print(res)

Python 라이브러리 ahocorasick은 사용하기 쉽고 UTF-8 문자 인코딩 문제를 해결하는 AC 자동화를 캡슐화합니다.

import ahocorasick


def build(patterns):
    trie = ahocorasick.Automaton()
    for index, word in enumerate(patterns):
        trie.add_word(word, (index, word))
    trie.make_automaton()
    return trie


if __name__ == '__main__':
    patterns = ['中国', '山东省', '威海市', '山东大学', '威海校区']
    text = '山东大学威海校区坐落于美丽滨城威海市。'
    trie = build(patterns)
    for each in trie.iter(text):
        print(each)

출력 결과:

(3, (3, '山东大学'))
(7, (4, '威海校区'))
(17, (2, '威海市'))

Supongo que te gusta

Origin blog.csdn.net/wwlsm_zql/article/details/131594899
Recomendado
Clasificación