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

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

.pdf
Скачиваний:
0
Добавлен:
09.09.2026
Размер:
248 Кб
Скачать
МИНОБРНАУКИ РОССИИ
САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ
ЭЛЕКТРОТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ
«ЛЭТИ» ИМ. В. И. УЛЬЯНОВА (ЛЕНИНА)
Кафедра МО ЭВМ
ОТЧЕТ
по дисциплине «Построение и анализ алгоритмов»
Тема: Алгоритм Кнута-Морриса-Пратта
Студентка гр. 2383
Бараева Е. Н.
Преподаватель
Шевелева А. М.
Санкт-Петербург
2024
2
Цель работы.
Изучить алгоритм Кнут-Моррис-Пратта для поиска подстроки в строке, и применить его для решения задачи об определении того, что является ли одна строка циклическим сдвигом другой.
Задание.
1) Реализуйте алгоритм КМП и с его помощью для заданных шаблона P
(P15000) и текста T (T5000000) найдите все вхождения P в T.
Вход:
Первая строка - P
Вторая строка - T
Выход:
индексы начал вхождений P в T, разделенных запятой, если P не входит в
T, то вывести −1
Sample Input:
ab
abab
Sample Output:
0,2
2) Заданы две строки A (A5000000) и B(B5000000).
Определить, является ли А циклическим сдвигом В (это значит, что А и
В имеют одинаковую длину и А состоит из суффикса В, склеенного с
префиксом В). Например, defabc является циклическим сдвигом abcdef.
Вход:
Первая строка - A
Вторая строка - B
Выход:
Если A является циклическим сдвигом B, индекс начала строки B в A, иначе вывести −1. Если возможно несколько сдвигов вывести первый индекс.
Sample Input:
3
defabc
abcdef
Sample Output:
3
Исследование: Анализ времени работы от длины строки и длины подстроки.
Выполнение работы.
prefix_function() – функция, которая вычисляет префикс-функцию для
заданного шаблона pattern. В начале инициализируется pattern_size размером pattern, k нулем, prefix_values массивом нулей. Переменная k будет использоваться для отслеживания текущего значения префикс­функции. В prefix_values будут храниться значения префикс-функции для каждой позиции в строке. Далее в цикле сравниваются символы строки, если они равны, то k увеличивается на 1 и его значение записывается в массив. Также в цикле сравниваются символы pattern[k] и pattern[i], если они не равны, то в k записывается значение из предыдущей позиции prefix_values. В конке возвращается список
prefix_values.
kmp_search() – функция алгоритма Кнут-Моррис-Пратта. В начале
инициализируется pattern_size, k также, как и в prefix_function. prefix_values инициализируется значением префикс-функции. Еще инициализируется пустой список result, в который будут добавляться индексы начала вхождений pattern в text. Далее цикл такой же, как и в prefix_function, но добавляется еще одно условие. В нем проверяется: если k достигает размера подстроки, то это означает, что нашлось вхождение подстроки в строку. Затем добавляется индекс начала вхождения в список result и обновляется значение k с помощью префикс-функции для последнего символа подстроки. В конце
4
возвращается список result, или -1, если ни одного вхождения не найдено.
В блоке if name == "main" производится ввод шаблона и текста, вызов
функции kmp_search(), и вывод индексов начала вхождений шаблона в текст.
is_cyclic_shift() – функция для 2 задания, которая сравнивает длины
подстроки и текста. Если они не равны, то возвращается -1, если равны, то подстрока удваивается, и функция возвращает вызов kmp_search().
Тестирование.
Результаты тестирования представлены в табл. 1. Таблица 1 – Результаты тестирования
№ п/п
Входные данные
Выходные
данные
Комментарии
1.
fk fkhkhskfsdjfksjfksjhfjsdhfkhsdskjds
0,11,15,25
Задание 1. Верно.
2.
asdfghjkl hjklasdfg
5
Задание 2. Верно.
3.
ewrtyuiopoiuy ewrtyuiopoiuqrwrtyuiopoiuy
-1
Задание 1. Верно.
4.
mnbvcxzlkjhgfdsapoiuytrewq vcxzlkjhgfdsapoiuytrewqmnn
-1
Задание 2. Верно.
Исследование.
Для проведения исследования был создан генератор случайных строк
определенной длины. Анализируя графики (см. рис. 1 и см. рис. 2) видно, что время выполнения работы алгоритма растёт линейно. Стоит заметить, что увеличение длины текста влияет на время меньше по сравнению с увеличением длины подстроки. Это можно объяснить тем, что самая затратная часть алгоритма – это вычисление префикс функции. Ее
5
вычисление зависит от длины подстроки, именно поэтому она тратит большое количество времени.
Рисунок 1 – Фиксированная длина текста и изменяющаяся длина
подстроки
Рисунок 2 – Фиксированная длина подстроки и изменяющаяся длина
текста
6
Вывод.
Был изучен алгоритм Кнута-Мориса-Пратта для поиска подстроки в строке.
Для этого в ходе выполнения лабораторной работы были написаны программы для определения того, является ли одна строка циклическим
сдвигом другой строки, и для поиска подстроки в строке. Также был создан
генератор тестов для тестирования и исследования написанных программ.
В ходе исследования выяснилось, что время выполнения работы алгоритма растёт линейно. Также было замечено, что увеличение длины текста влияет на время меньше по сравнению с увеличением длины подстроки. В добавок выяснилось, что вычисление префикс функции – это самая затратная часть алгоритма. Таким образом алгоритм Кнута-Мориса-Пратта для поиска подстроки в
строке может быть максимально эффективно использован при относительно
небольших размерах подстроки, однако даже при больших размерах подстроки позволяет выполнять поиск за линейное время и превосходить по скорости наивный поиск.
7
ПРИЛОЖЕНИЕ А
ИСХОДНЫЙ КОД ПРОГРАММЫ
Название файла: kmp.py
def prefix_function(pattern): pattern_size, k = len(pattern), 0 prefix_values = [0] * pattern_size
for i in range(1, pattern_size): while k > 0 and pattern[k] != pattern[i]: k = prefix_values[k - 1] if pattern[k] == pattern[i]: k += 1 prefix_values[i] = k
return prefix_values
def kmp_search(): pattern_size, k = len(pattern), 0 prefix_values = prefix_function(pattern) result = []
for i in range(len(text)): while k > 0 and pattern[k] != text[i]: k = prefix_values[k - 1] if pattern[k] == text[i]: k += 1 if k == pattern_size: result.append(i - pattern_size + 1) k = prefix_values[k - 1]
return result if result else [-1]
if __name__ == '__main__': pattern = input() text = input() indices = kmp_search()
print(','.join(map(str, indices)))
Название файла: cycle.py
from kmp import prefix_function
def kmp_search(text, pattern):
pattern_size, k = len(pattern), 0
prefix_values = prefix_function(pattern)
for i in range(len(text)):
while k > 0 and pattern[k] != text[i]:
k = prefix_values[k - 1]
if pattern[k] == text[i]:
k += 1
if k == pattern_size:
8
return i - pattern_size + 1
return -1
def is_cyclic_shift():
if len(first) != len(second):
return -1
double_first = first + first
return kmp_search(double_first, second)
if __name__ == '__main__':
first = input()
second = input() print(is_cyclic_shift())
Соседние файлы в папке Лабы по ПиАА 2024