Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лабы по ПиАА 2024 / Baraeva_Elizaveta_lb5

.pdf
Скачиваний:
0
Добавлен:
09.09.2026
Размер:
242 Кб
Скачать
МИНОБРНАУКИ РОССИИ
САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ
ЭЛЕКТРОТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ
«ЛЭТИ» ИМ. В. И. УЛЬЯНОВА (ЛЕНИНА)
Кафедра МО ЭВМ
ОТЧЕТ
по дисциплине «Построение и анализ алгоритмов»
Тема: Алгоритм Ахо-Корасик
Студентка гр. 2383
Бараева Е. Н.
Преподаватель
Шевелева А. М.
Санкт-Петербург
2024
2
Цель работы.
Изучить алгоритм Ахо-Корасик для решения задачи точного поиска набора образцов в тексте и решения задачи точного поиска набора образцов в тексте с джокером.
Задание.
1) Разработайте программу, решающую задачу точного поиска набора
образцов.
Вход:
Первая строка содержит текст (T,1≤T100000 ).
Вторая - число 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≤T100000 )
Шаблон (P,1≤P40)
Символ джокера
Выход:
Строки с номерами позиций вхождений шаблона (каждая строка
содержит только один номер).
Номера должны выводиться в порядке возрастания.
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