Добавил:
baraevaliza
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Лабы по ПиАА 2024 / Baraeva_Elizaveta_lb5
.pdf
МИНОБРНАУКИ РОССИИ
САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ
ЭЛЕКТРОТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ
«ЛЭТИ» ИМ. В. И. УЛЬЯНОВА (ЛЕНИНА)
Кафедра МО ЭВМ
ОТЧЕТ
по лабораторной работе №5
по дисциплине «Построение и анализ алгоритмов»
Тема: Алгоритм Ахо-Корасик
Студентка гр. 2383
Бараева Е. Н.
Преподаватель
Шевелева А. М.
Санкт-Петербург
2024

2
Цель работы.
Изучить алгоритм Ахо-Корасик для решения задачи точного поиска
набора образцов в тексте и решения задачи точного поиска набора образцов в
тексте с джокером.
Задание.
1) Разработайте программу, решающую задачу точного поиска набора
образцов.
Вход:
Первая строка содержит текст (T,1≤∣T∣≤100000 ).
Вторая - число n (1≤n≤3000), каждая следующая из n строк содержит
шаблон из набора P={p1, … ,pn}1≤∣pi∣≤75
Все строки содержат символы из алфавита {A,C,G,T,N}
Выход:
Все вхождения образцов из P в T.
Каждое вхождение образца в текст представить в виде двух чисел - i p
Где i - позиция в тексте (нумерация начинается с 1), с которой
начинается вхождение образца с номером p (нумерация образцов начинается
с 1).
Строки выхода должны быть отсортированы по возрастанию, сначала
номера позиции, затем номера шаблона.
Sample Input:
NTAG
3
TAGT
TAG
T
Sample Output:
2 2
2 3

3
2) Используя реализацию точного множественного поиска, решите
задачу точного поиска для одного образца с джокером.
В шаблоне встречается специальный символ, именуемый джокером (wild
card), который "совпадает" с любым символом. По заданному содержащему
шаблоны образцу P необходимо найти все вхождения Р в текст Т.
Например, образец аb??с? с джокером ? встречается дважды в тексте
xabvccbababcax.
Символ джокер не входит в алфавит, символы которого используются в T.
Каждый джокер соответствует одному символу, а не подстроке
неопределённой длины. В шаблон входит хотя бы один символ не джокер, т.е.
шаблоны вида ??? недопустимы.
Все строки содержат символы из алфавита {A,C,G,T,N}
Вход:
Текст (T,1≤∣T∣≤100000 )
Шаблон (P,1≤∣P∣≤40)
Символ джокера
Выход:
Строки с номерами позиций вхождений шаблона (каждая строка
содержит только один номер).
Номера должны выводиться в порядке возрастания.
Sample Input:
ACTANCA
A$$A$
$
Sample Output:
1
Исследование: на месте джокера может быть любой символ, за
исключением заданного.

4
Выполнение работы.
• класс Node – класс, который представляет узел в дереве Trie. Узел
содержит список слов, дочерние узлы и суффиксную ссылку.
• класс Trie – класс, который включает методы инициализации и
создания бора, а также установки связей между узлами.
• create_tree – метод, в котором происходит построение бора на основе
переданных шаблонов. Каждый символ шаблона добавляется в
дочерний узел текущего узла.
• create_links – метод, который устанавливает связи узлов с помощью
суффиксных ссылок. Для этого используется очередь queue, в которую
добавляются все дочерние узлы корневого узла. Затем происходит
обход дерева и установка суффиксных ссылок для каждого узла.
• find_start – метод, который позволяет искать совпадения начинающиеся
с определенного символа в тексте.
• run_aho_corasick – функция, в которой создается экземпляр класса Trie,
инициализируется алгоритм Ахо-Корасик, создается массив ответа с
индексами вхождения и паттернов.
• split_pattern – функция, которая разбивает шаблон на части по маске и
возвращает индексы найденных масок в шаблоне, а также сами
подшаблоны.
• find_entries – функция, находит все вхождения паттернов в текст с
помощью алгоритма Ахо-Корасик, и возвращает позиции начала
вхождений паттернов в тексте.
• find_pattern – функция, которая ищет все вхождения шаблона в тексте с
джокером. Она перебирает все возможные стартовые позиции в тексте
и проверяет, совпадает ли шаблон с текстом на этой позиции. Если
вхождение соответствует шаблону, то индекс начала этого вхождения
добавляется в результаты. В конце функция возвращает список
результатов.

5
Тестирование.
Результаты тестирования представлены в табл. 1.
Таблица 1 – Результаты тестирования
№ п/п
Входные данные
Выходные данные
Комментарии
1.
NTAG
3
TAGT
TAG
T
2 2
2 3
Задание 1.
Верно.
2.
ACTANCA
A$$A$
$
1
Задание 2.
Верно.
3.
ACGTNNNACGTTAGNC
3
GNCA
NNN
ACGTNNNACGTTAGNC
1 3
5 2
Задание 1.
Верно.
4.
ACGAGAGAGANTTTANA
G&&
&
3
5
7
9
Задание 2.
Верно.
Вывод.
Был изучен и реализован алгоритм Ахо-Корасик для поиска набора
образцов в тексте, а также для одного образца с джокером. Была изучена
такая ключевая структура данных, как бор, а также изучено построение
конечного автомата. Использование данных техник позволило достичь
линейной скорости поиска множества образцов в тексте за счёт
предварительной обработки. Алгоритм Ахо-Корасик наиболее эффективен в
ситуациях, когда требуется выполнить множество поисковых запросов по
одному и тому же набору паттернов в различных текстах. Это особенно
полезно, когда набор паттернов не изменяется, а количество текстов для
поиска велико. Использование алгоритма Ахо-Корасик позволяет избежать
повторной предварительной обработки паттернов для каждого отдельного
текста, что значительно ускоряет процесс поиска.

6
ПРИЛОЖЕНИЕ А
ИСХОДНЫЙ КОД ПРОГРАММЫ
Название файла: aho.py
from collections import deque
class Node:
def __init__(self, suffix_link=None):
self.words = []
self.child = {}
self.suffix_link = suffix_link
class Trie:
def __init__(self, patterns):
self.root = Node()
self.node = self.root
self.create_tree(patterns)
self.create_links()
def create_tree(self, patterns):
for index, pattern in enumerate(patterns):
node = self.root
for symbol in pattern:
if symbol not in node.child:
node.child[symbol] = Node(self.root)
node = node.child[symbol]
node.words.append(index)
def create_links(self):
queue = deque()
for _, node in self.root.child.items():
queue.append(node)
while queue:
current_node = queue.popleft()
for symbol, node in current_node.child.items():
link_node = current_node.suffix_link
while link_node is not None and symbol not in
link_node.child:
link_node = link_node.suffix_link
if link_node is not None:
node.suffix_link = link_node.child[symbol]
else:
node.suffix_link = self.root
node.words.extend(node.suffix_link.words)
queue.append(node)
def find_start(self, symbol):
while self.node is not None and symbol not in
self.node.child:
self.node = self.node.suffix_link
if self.node is None:

7
self.node = self.root
return None
self.node = self.node.child[symbol]
return self.node
def run_aho_corasick(text, patterns):
trie = Trie(patterns)
answer = []
for index, symbol in enumerate(text):
node = trie.find_start(symbol)
if node:
for pattern_index in node.words:
answer.append((index + 2 -
len(patterns[pattern_index]), pattern_index + 1))
return answer
if __name__ == "__main__":
text = input()
n = int(input())
patterns = [input() for _ in range(n)]
answer = run_aho_corasick(text, patterns)
answer.sort()
for index, pattern_index in answer:
print(index, pattern_index)
Название файла: aho_wild_card.py
from collections import deque
class Node:
def __init__(self, suffix_link=None):
self.words = []
self.child = {}
self.suffix_link = suffix_link
class Trie:
def __init__(self, patterns):
self.root = Node()
self.node = self.root
self.create_tree(patterns)
self.create_links()
def create_tree(self, patterns):
for index, pattern in enumerate(patterns):
node = self.root
for symbol in pattern:
if symbol not in node.child:
node.child[symbol] = Node(self.root)
node = node.child[symbol]
node.words.append(index)

8
def create_links(self):
queue = deque()
for _, node in self.root.child.items():
queue.append(node)
while queue:
current_node = queue.popleft()
for symbol, node in current_node.child.items():
link_node = current_node.suffix_link
while link_node is not None and symbol not in
link_node.child:
link_node = link_node.suffix_link
if link_node is not None:
node.suffix_link = link_node.child[symbol]
else:
node.suffix_link = self.root
node.words.extend(node.suffix_link.words)
queue.append(node)
def find_start(self, symbol):
while self.node is not None and symbol not in
self.node.child:
self.node = self.node.suffix_link
if self.node is None:
self.node = self.root
return None
self.node = self.node.child[symbol]
return self.node
def run_aho_corasick(text, patterns):
trie = Trie(patterns)
answer = []
for index in range(len(text)):
node = trie.find_start(text[index])
if node:
for pattern_index in node.words:
answer.append((index + 1 len(patterns[pattern_index]), pattern_index))
answer.sort()
return answer
def split_pattern(pattern, wild_card):
indices = []
patterns = []
old_index = -1
tmp = ""
for i in range(len(pattern)):
if pattern[i] == wild_card and tmp:
indices.append(old_index)

9
patterns.append(tmp)
tmp = ""
old_index = -1
elif pattern[i] != wild_card:
old_index = i if old_index == -1 else old_index
tmp += pattern[i]
if tmp:
indices.append(old_index)
patterns.append(tmp)
return indices, patterns
def find_entries(text, pattern, wild_card):
result = []
occurrences = [0] * len(text)
entry_indices, patterns = split_pattern(pattern, wild_card)
entries = run_aho_corasick(text, patterns)
for index, pattern_index in entries:
text_idx = index - entry_indices[pattern_index]
if 0 <= text_idx < len(occurrences):
occurrences[text_idx] += 1
for i in range(len(occurrences) - len(pattern) + 1):
if occurrences[i] == len(patterns):
result.append(i + 1)
return result
if __name__ == "__main__":
text = input()
pattern = input()
wild_card = input()
answer = find_entries(text, pattern, wild_card)
for i in answer:
print(i)
Соседние файлы в папке Лабы по ПиАА 2024
