Поиск подстрок

Метод прямого поиска и метод Рабина-Карпа

Требования к заданию на GitHub

Ход выполнения

Начало файла, константы и вспомогательные функции

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

char initial_string[] = "justregulartextjustfindinthistextjustworditsjustaword";
char initial_substring[] = "just";

/*
  Сравнивает две строки, возвращает true в случае равенства

  param: comp - указатель на счетчик сравнений
*/
bool compare(const char *haystack, int start, const char *needle, int m, int *comp)
{
    for (int i = 0; i < m; i++)
    {
        (*comp)++;
        if (haystack[start + i] != needle[i])
        {
            return false;
        }
    }
    return true;
}

/*
  Возвращает хеш-значение подстроки.
  Использует модуль q для предотвращения переполнения.
  Каждый символ рассматривается как байт (unsigned char), а база для хеширования — 256.

  param: start - начальный индекс подстроки
  param: end - конечный индекс подстроки (включительно)
  param: q - модуль для вычисления хеша
*/
int hash_string(const char *str, int start, int end, int q)
{
    int hash = 0;
    for (int i = start; i <= end; i++)
    {
        hash = (hash * 256 + (unsigned char)str[i]) % q;
    }
    return hash;
}
  1. Реализовать поиск всех подстрок в тексте методом прямого поиска (перебором).
    Вывести на экран текст, подстроку и индексы начала вхождения подстроки в текст.
int direct_search(char *string, char *substring)
{
    printf("\033[32m \033[21mDirect search:\033[0m\n");
    int string_len = strlen(string);
    int substring_len = strlen(substring);
    printf("\033[34mString text:\033[0m%s\n", string);
    printf("\033[34mSubstring text:\033[0m%s\n", substring);
    printf("\033[33mLen of string is\033[0m %d chars\n", string_len);
    printf("\033[33mLen of substring is\033[0m %d chars\n", substring_len);
    int direct_comp = 0;
    for (int i = 0; i <= string_len - substring_len; i++)
    {
        if (compare(string, i, substring, substring_len, &direct_comp))
        {
            printf("\033[36mFound substring at index\033[0m \033[1m%d\033[0m\n", i);
        }
    }
    printf("\033[35mTotal comparisons in Direct search: %d\033[0m\n", direct_comp);
    return -1;
}
  1. Реализовать поиск всех подстрок в тексте методом Рабина-Карпа.
    Вывести на экран текст, подстроку и индексы начала вхождения подстроки в текст.
int RabinKarp(char *haystack, char *needle, int q)
{
    printf("\033[32m \033[21mRabinKarp search (q=%d):\033[0m\n", q);
    printf("\033[34mString text:\033[0m%s\n", haystack);
    printf("\033[34mSubstring text:\033[0m%s\n", needle);
    int m = strlen(needle);
    int n = strlen(haystack);
    int RabinKarp_comp = 0;
    int hash_needle = hash_string(needle, 0, m - 1, q);
    int hash_haystack = hash_string(haystack, 0, m - 1, q);
    for (int i = 0; i <= n - m; i++)
    {
        if (hash_haystack == hash_needle)
        {
            if (compare(haystack, i, needle, m, &RabinKarp_comp))
            {
                printf("\033[36mFound substring at index\033[0m \033[1m%d\033[0m\n", i);
            }
        }
        if (i < n - m)
        {
            hash_haystack = hash_string(haystack, i + 1, i + m, q);
        }
    }
    printf("\033[35mTotal comparisons in RabinKarp: %d\033[0m\n", RabinKarp_comp);
    return -1;
}
  1. Подсчитать и сравнить количество посимвольных сравнений подстроки в ходе поиска методом перебора и методом Рабина-Карпа при разных значениях q.
  int main()
  {
      int q[10] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
      direct_search(initial_string, initial_substring);
      for (int i = 0; i < 10; i++)
      {
          RabinKarp(initial_string, initial_substring, q[i]);
      }
  }
  1. Дополнительное задание (на 5+):
    Оценить зависимость трудоемкости поиска от длины подстроки в методе Рабина-Карпа.

Полный текст программы

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

char initial_string[] = "justregulartextjustfindinthistextjustworditsjustaword";
char initial_substring[] = "just";

bool compare(const char *haystack, int start, const char *needle, int m, int *comp)
{
    for (int i = 0; i < m; i++)
    {
        (*comp)++;
        if (haystack[start + i] != needle[i])
        {
            return false;
        }
    }
    return true;
}

int direct_search(char *string, char *substring)
{
    printf("\033[32m \033[21mDirect search:\033[0m\n");
    int string_len = strlen(string);
    int substring_len = strlen(substring);
    printf("\033[34mString text:\033[0m%s\n", string);
    printf("\033[34mSubstring text:\033[0m%s\n", substring);
    printf("\033[33mLen of string is\033[0m %d chars\n", string_len);
    printf("\033[33mLen of substring is\033[0m %d chars\n", substring_len);
    int direct_comp = 0;
    for (int i = 0; i <= string_len - substring_len; i++)
    {
        if (compare(string, i, substring, substring_len, &direct_comp))
        {
            printf("\033[36mFound substring at index\033[0m \033[1m%d\033[0m\n", i);
        }
    }
    printf("\033[35mTotal comparisons in Direct search: %d\033[0m\n", direct_comp);
    return -1;
}

int hash_string(const char *str, int start, int end, int q)
{
    int hash = 0;
    for (int i = start; i <= end; i++)
    {
        hash = (hash * 256 + (unsigned char)str[i]) % q;
    }
    return hash;
}

int RabinKarp(char *haystack, char *needle, int q)
{
    printf("\033[32m \033[21mRabinKarp search (q=%d):\033[0m\n", q);
    printf("\033[34mString text:\033[0m%s\n", haystack);
    printf("\033[34mSubstring text:\033[0m%s\n", needle);
    int m = strlen(needle);
    int n = strlen(haystack);
    int RabinKarp_comp = 0;
    int hash_needle = hash_string(needle, 0, m - 1, q);
    int hash_haystack = hash_string(haystack, 0, m - 1, q);
    for (int i = 0; i <= n - m; i++)
    {
        if (hash_haystack == hash_needle)
        {
            if (compare(haystack, i, needle, m, &RabinKarp_comp))
            {
                printf("\033[36mFound substring at index\033[0m \033[1m%d\033[0m\n", i);
            }
        }
        if (i < n - m)
        {
            hash_haystack = hash_string(haystack, i + 1, i + m, q);
        }
    }
    printf("\033[35mTotal comparisons in RabinKarp: %d\033[0m\n", RabinKarp_comp);
    return -1;
}

int main()
{
    int q[10] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
    direct_search(initial_string, initial_substring);
    for (int i = 0; i < 10; i++)
    {
        RabinKarp(initial_string, initial_substring, q[i]);
    }
}