Описание программы
Работа была выполнена на языке программирования C++ с использованием среды разработки Visual Studio Community 2022 версии 17.7.4.
Использованные библиотеки: iostream, cstdlib, ctime, chrono, locale
Сама программа включает в себя несколько функций, как:
int find_substrings(string S, string W)
int KMPSearch(char *string, char *substring)
char getRandomChar()
Функция 1 является алгоритмом прямого поиска. Прямой поиск осуществляется путем сравнения каждого символа подстроки с символами строки. Если символы не совпадают, то происходит сдвиг и поиск продолжается со следующего символа в строке. Этот алгоритм позволяет найти первое вхождение подстроки в строке и может быть эффективен для не слишком длинных строк и коротких подстрок. В качестве результата возвращает индекс первого элемента, с которого пошло совпадение. В обратном случае возвращается «-1», что сигнализирует об отсутствии результата.
Функция 2 является алгоритмом Кнута-Морриса-Пратта и работает по такому же принципу, что и функция 1 – получает ссылки на массив основной строки и подстроки, возвращает результат.
Функция 3 является служебной функцией, используемой для заполнения массивов строки и подстроки. При помощи метода rand библиотеки stdlib.h возвращает случайный символ из 52 символов – строчных и заглавных латинских букв.
В int main() происходят основные операции, необходимые для выполнения поставленной задачи: здесь инициализируется количество повторов (int times) и количество шагов. Далее инициализируются динамические массивы для хранения результатов подсчета времени для КМП и Прямого соответственно chrono::duration<double, milli> bruteforce_time = end - start; и chrono::duration<double, milli> kmp_time = end – start.
После этого цикла нет необходимости в какой-либо дальнейшей обработке, поэтому полученные результаты выводятся на консоль посредством функции printf. После всех проделанных манипуляций освобождается память от занятых динамических массивов и завершается работа программы.
Сравнение и тестирование
Пример реализации методов поиска подстроки (таблица 3).
Подстрока: АВСАВD |
|
||
Текст для поиска: |
ABCABCAABCABD |
|
|
Алгоритм Кнута-Морриса-Пратта |
|||
Префикс-функция: |
"000120" |
|
|
Процесс поиска: |
Шаг 1 |
ABCABCAABCABD |
|
|
|
Шаг 2 |
ABCABCAABCABD |
|
|
Шаг 3 |
ABCABCAABCABD |
|
|
Шаг 4 |
ABCABCAABCABD |
Алгоритм прямого поиска |
|||
Процесс поиска: |
Шаг 1 |
ABCABCAABCABD |
|
|
|
Шаг 2 |
АВСАВD |
|
|
Шаг 3 |
АВСАВD |
|
|
Шаг 4 |
АВСАВD |
|
|
Шаг 5 |
АВСАВD |
|
|
Шаг 6 |
АВСАВD |
|
|
Шаг 7 |
АВСАВD |
|
|
Шаг 8 |
АВСАВD |
|
|
Шаг 9 |
АВСАВD |
|
|
Шаг 10 |
АВСАВD |
|
|
Шаг 11 |
АВСАВD |
|
|
Шаг 12 |
АВСАВD |
|
|
Шаг 13 |
АВСАВD |
|
|
Шаг 14 |
АВСАВD |
|
|
Шаг 15 |
АВСАВD |
|
|
Шаг 16 |
АВСАВD |
|
|
Шаг 17 |
АВСАВD |
|
|
Шаг 18 |
АВСАВD |
|
|
Шаг 19 |
АВСАВD |
|
|
Шаг 20 |
АВСАВD |
|
|
Шаг 21 |
АВСАВD |
Таблица 3. Сравнение алгоритмов
Алгоритм прямого поиска
На первом шаге происходит сравнение первых шести символов строки и подстроки: это ABCABD и ABCABC. Совпадает первый символ.
Со второго шага начинается посимвольное сравнение строки и подстроки. Если найдено совпадение, то позиция не сдвигается, а сравнивается следующий символ подстроки со строкой, и так до тех пор, пока не будет обнаружено полное совпадение или его отсутствие. В нашем случае на втором шаге фиксируется совпадение первого символа подстроки «А», на третьем шаге — второго символа «B», на четвёртом шаге — символа «С», на пятом шаге — символа «А», на шестом шаге — символа «В».
На седьмом шаге происходит сдвиг на одну позицию, так как шестой символ строки не совпал с последним символом подстроки. На этом шаге сравнивается ABCABD и BCABCA. Совпадения нет.
На восьмом шаге происходит сдвиг на одну позицию, так как в текущей позиции совпадений нет. На этом шаге сравнивается ABCABD и CABCAA.
На девятом шаге происходит сравнение четвёртого символа строки и первого символа подстроки. Найдено совпадение символа «А». В нашем случае на десятом шаге фиксируется совпадение второго символа «B», на одиннадцатом шаге — символа «С», на двенадцатом шаге — символа «А». Совпадение закончилось, происходит сдвиг.
На тринадцатом шаге происходит сдвиг, так как совпадений нет. На этом шаге происходит сравнение ABCABD и BCAABC.
На четырнадцатом шаге сравнивается ABCABD и CAABCA. Совпадение не найдено, происходит сдвиг.
На пятнадцатом шаге сравнивается ABCABD и AABCAB. Совпадение не найдено, происходит сдвиг.
На шестнадцатом шаге сравнивается ABCABD и ABCABD. Фиксируется совпадение первого символа. На семнадцатом шаге фиксируется совпадение второго символа «B», на восемнадцатом шаге — символа «С», на девятнадцатом шаге — символа «А», на двадцатом — символа «B», на двадцать первом шаге — символа «D». Найдено полное совпадение.
Алгоритм Кнута-Морриса-Пратта
Предобработка. Составление префикс-функции.
Для 1 элемента подстроки сравним префикс (желтый) и суффикс (зеленый). ABCABD – совпадения нет, значение равно 0.
Для 2 элемента подстроки: ABCABD. Не забываем, что префикс и суффикс могут пересекаться, однако, АB не равняется BC. Совпадения нет, значение = 0.
Для 3 элемента подстроки: ABCABD. Совпадение есть, сравнение дальше: ABCABD. Совпадения нет, при дальнейшем сравнении тоже, значение = 1.
Для 4 элемента подстроки: ABCABD. Не совпадает, сравнение дальше: ABCABD. Совпадают 2 элемента, при дальнейшем сравнении перемен не будет, значение = 2.
Для 5 элемента подстроки: ABCABD. Совпадения нет, при дальнейшем сравнении тоже, значение = 0.
В итоге, для ABCABD массив значений префикс-функции выглядит следующим образом: 000120.
После этого осуществляется сам поиск подстроки в строке ABCABCAABCABD. На первом шаге сравнивается ABCABD и ABCABC. Не совпадает элемент 5. Значение префикс-функции для предыдущего элемента = 2. Переносим всю подстроку вправо так, что она будет начинаться на 2 элемента левее места несовпадения, т.е., сдвигая на 2 элемента влево.
На втором шаге поиска сравнивается ABCABD и ABCAAB. Не совпадает элемент 4. Значение префикс-функции для предыдущего элемента = 1. Переносим всю строку вправо так, что она будет начинаться на 1 элемент левее места несовпадения, т.е., сдвигая на 1 элемент влево.
На третьем шаге сравнивается ABCABD и AABCAB. Несовпадение на элементе 1. Значение префикс-функции для предыдущего элемента = 0. Переносим всю строку вправо так, что она будет начинаться на месте несовпадения, т.е., без сдвига.
На четвертом шаге сравнивается ABCABD и ABCABD. Совпадение, подстрока найдена.
