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

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

.doc
Скачиваний:
0
Добавлен:
09.09.2026
Размер:
86 Кб
Скачать

МИНОБРНАУКИ РОССИИ

Санкт-Петербургский государственный

электротехнический университет

«ЛЭТИ» им. В. И. Ульянова (Ленина)

Кафедра МО ЭВМ

отчет

по лабораторной работе №4

по дисциплине «Построение и анализ алгоритмов»

Тема: Алгоритм Кнута-Морриса-Пратта

Студентка гр. 2383

Бараева Е. Н.

Преподаватель

Шевелева А. М.

Санкт-Петербург

2024

Цель работы.

Изучить алгоритм Кнут-Моррис-Пратта для поиска подстроки в строке, и применить его для решения задачи об определении того, что является ли одна строка циклическим сдвигом другой.

Задание.

1) Реализуйте алгоритм КМП и с его помощью для заданных шаблона P (∣P∣≤15000) и текста T (∣T∣≤5000000) найдите все вхождения P в T.

Вход:

Первая строка - P

Вторая строка - T

Выход:

индексы начал вхождений P в T, разделенных запятой, если P не входит в T, то вывести −1

Sample Input:

ab

abab

Sample Output:

0,2

2) Заданы две строки A (∣A∣≤5000000) и B(∣B∣≤5000000).

Определить, является ли А циклическим сдвигом В (это значит, что А и В имеют одинаковую длину и А состоит из суффикса В, склеенного с префиксом В). Например, defabc является циклическим сдвигом abcdef.

Вход:

Первая строка - A

Вторая строка - B

Выход:

Если A является циклическим сдвигом B, индекс начала строки B в A, иначе вывести −1. Если возможно несколько сдвигов вывести первый индекс.

Sample Input:

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 с помощью префикс-функции для последнего символа подстроки. В конце возвращается список 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) видно, что время выполнения работы алгоритма растёт линейно. Стоит заметить, что увеличение длины текста влияет на время меньше по сравнению с увеличением длины подстроки. Это можно объяснить тем, что самая затратная часть алгоритма – это вычисление префикс функции. Ее вычисление зависит от длины подстроки, именно поэтому она тратит большое количество времени.

Рисунок 1 – Фиксированная длина текста и изменяющаяся длина подстроки

Рисунок 2 – Фиксированная длина подстроки и изменяющаяся длина текста

Вывод.

Был изучен алгоритм Кнута-Мориса-Пратта для поиска подстроки в строке.

Для этого в ходе выполнения лабораторной работы были написаны программы для определения того, является ли одна строка циклическим сдвигом другой строки, и для поиска подстроки в строке. Также был создан генератор тестов для тестирования и исследования написанных программ.

В ходе исследования выяснилось, что время выполнения работы алгоритма растёт линейно. Также было замечено, что увеличение длины текста влияет на время меньше по сравнению с увеличением длины подстроки. В добавок выяснилось, что вычисление префикс функции – это самая затратная часть алгоритма.

Таким образом алгоритм Кнута-Мориса-Пратта для поиска подстроки в строке может быть максимально эффективно использован при относительно небольших размерах подстроки, однако даже при больших размерах подстроки позволяет выполнять поиск за линейное время и превосходить по скорости наивный поиск.

ПРИЛОЖЕНИЕ А ИСХОДНЫЙ КОД ПРОГРАММЫ

Название файла: 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:

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())

8

Соседние файлы в папке Лабы по ПиАА 2024