Результаты работы
В ходе выполнения поставленной задачи были получены следующие результаты:
Размер
массива
Время
Рис. 5. Сравнение временных затрат на поиск алгоритмами КМП и Прямой
На рис. 5 синим цветом отмечен алгоритм Прямой, оранжевым – КМП. Согласно информации с графика, Прямой алгоритм медленнее алгоритма КМП. Также стоит отметить, что прямой алгоритм сильнее замедляется с увеличением размерности строки. В связи с этим можно сказать, что прямой алгоритм в среднестатистической ситуации, когда искомая подстрока может находиться, как в начале, так и в любой другой части строки, предпочтительнее КМП благодаря своей более низкой сложности.
Вывод
В ходе проведенной лабораторной работы была достигнута цель изучения и практического сравнения эффективности алгоритмов. Реализация и тестирование различных программ позволило подтвердить теоретические оценки их временной сложности.
Приложение
#include <iostream>
#include <string>
#include <ctime>
#include <chrono>
#include <random>
#include <locale.h>
using namespace std;
// Функция для генерации случайного символа
char getRandomChar() {
const char str[] = { 'A', 'a', 'B', 'b', 'C', 'c', 'D', 'd', 'E', 'e', 'F', 'f', 'G', 'g', 'H', 'h', 'I', 'i', 'J', 'j', 'K', 'k', 'L', 'l', 'M', 'm', 'N', 'n', 'O', 'o', 'P', 'p', 'Q', 'q', 'R', 'r', 'S', 's', 'T', 't', 'U', 'u', 'V', 'v', 'W', 'w', 'X', 'x', 'Y', 'y', 'Z', 'z' };
return str[rand() % 52];
}
// Алгоритм прямого поиска
int find_substrings(string S, string W) {
unsigned int i, j;
int number = 0;
for (i = 0; i < S.length() - W.length() + 1; i++) {
j = 0;
while ((j < W.length()) && (W[j] == S[i + j])) {
j = j + 1;
}
if (j == W.length()) {
number++;
}
}
return number;
}
// Алгоритм Кнута-Морриса-Пратта
int KMPSearch(string text, string pattern) {
int n = text.length();
int m = pattern.length();
int count = 0;
// Создаем префикс-функцию
vector<int> pi(m);
pi[0] = 0;
int k = 0;
for (int i = 1; i < m; i++) {
while (k > 0 && pattern[k] != pattern[i])
k = pi[k - 1];
if (pattern[k] == pattern[i])
k++;
pi[i] = k;
}
// Поиск подстроки
k = 0;
for (int i = 0; i < n; i++) {
while (k > 0 && pattern[k] != text[i])
k = pi[k - 1];
if (pattern[k] == text[i])
k++;
if (k == m) {
count++;
k = pi[k - 1];
}
}
return count;
}
int main() {
setlocale(LC_ALL, "Russian");
srand(time(0));
int n;
cout << "Введите длину текста: ";
cin >> n;
// Генерация случайной подстроки длиной 4
string pattern = "";
for (int i = 0; i < 4; i++) {
pattern += getRandomChar();
}
// Создание текста с вставленной подстрокой каждые 30 символов
string text = "";
for (int i = 0; i < n; i++) {
if (i % 30 == 0 && i + 4 <= n) {
text += pattern;
i += 3; // Пропускаем 3 позиции, т.к. четвертая будет пропущена в цикле
}
else {
text += getRandomChar();
}
}
// Замер времени для прямого поиска
auto start = chrono::high_resolution_clock::now();
int count1 = find_substrings(text, pattern);
auto end = chrono::high_resolution_clock::now();
chrono::duration<double, milli> bruteforce_time = end - start;
// Замер времени для алгоритма КМП
start = chrono::high_resolution_clock::now();
int count2 = KMPSearch(text, pattern);
end = chrono::high_resolution_clock::now();
chrono::duration<double, milli> kmp_time = end - start;
cout << "Искомая подстрока: " << pattern << endl;
cout << "\nРезультаты поиска:" << endl;
cout << "Прямой поиск нашел " << count1 << " вхождений за "
<< bruteforce_time.count() << " мс" << endl;
cout << "Алгоритм КМП нашел " << count2 << " вхождений за "
<< kmp_time.count() << " мс" << endl;
return 0;
}
Санкт-Петербург
2025
