Добавил:
СПбГУТ * ИКСС * Программная инженерия Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Коды основных функций / [Код основных функций] Лаб. 2. Часть 2

.pdf
Скачиваний:
43
Добавлен:
03.08.2020
Размер:
86.67 Кб
Скачать

[Код основных функций] Лабораторная работа №2. Часть 2. Поиск подстрок

//Get the current time.

//This function should be used only for measuring time

//(first call, algorithm, second call; then the difference between the values) double getProcTime() {

#if defined(_WIN32) // If Windows:

FILETIME createTime, exitTime, kernelTime, userTime;

if (GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime) != -1)

return (ULARGE_INTEGER { {userTime.dwLowDateTime, userTime.dwHighDateTime } }).QuadPart / 10000000.L;

return 0;

#else // If Linux or MacOS:

return double(clock()) / CLOCKS_PER_SEC; #endif

}

//Standard search

template <class T = std::string>

int standardSearch(const T & str, const T & substr, int pos = 0) noexcept { return str.find(substr, pos);

}

// Direct search

template <class T = std::string>

int directSearch(const T & str, const T & substr, int pos = 0) { const int n = str.size() - pos, m = substr.size();

if (m == 0) return (n >= 0) ? pos : -1; if (n <= 0 || n < m) return -1;

for (int i, j = 0, end = n - m; j <= end; ++j) {

for (i = 0; i < m && str[i + j + pos] == substr[i]; ++i); if (i < m) continue;

return j + pos;

}

return -1;

}

// Boyer-Moore-Horspool search template <class T = std::string>

int boyerMooreHorspoolSearch(const T & str, const T & substr, int pos = 0) { const int n = str.size() - pos, m = substr.size();

if (m == 0) return (n >= 0) ? pos : -1; if (n <= 0 || n < m) return -1;

int * badchar = new int[UCHAR_MAX + 1];

// memset. Attention! The second argument is interpreted as unsigned char. -1 : 0xFF. memset(badchar, -1, sizeof(int) * (UCHAR_MAX + 1));

for (int i = 0; i < m; ++i) badchar[(unsigned char) substr[i]] = i;

for (int s = 0, j, end = n - m; s <= end; s += std::max(1, j - badchar[(unsigned char) str[s + j + pos]])) {

for (j = m - 1; j >= 0 && str[s + j + pos] == substr[j]; --j); if (j >= 0) continue;

delete[] badchar; return s + pos;

}

delete[] badchar; return -1;

}

//Apostolico-Crochemore search template <class T = std::string>

int apostolicoCrochemoreSearch(const T & str, const T & substr, int pos = 0) { const int n = str.size() - pos, m = substr.size();

if (m == 0) return (n >= 0) ? pos : -1; if (n <= 0 || n < m) return -1;

int * taggedBorder = new int[m + 1];

for (int i = 0, j = taggedBorder[0] = -1; i < m; ) { while (j >= 0 && substr[i] != substr[j])

j = taggedBorder[j]; ++i, ++j;

taggedBorder[i] = (i < m && substr[i] == substr[j]) ? taggedBorder[j] : j;

}

int L;

for (L = 1; L < m && substr[L - 1] == substr[L]; ++L); if (L == m) L = 0;

for (int i = L, j = 0, k = 0, end = n - m; j <= end; ) { while (i < m && substr[i] == str[i + j + pos]) ++i; if (i >= m) {

while (k < L && substr[k] == str[j + k + pos]) ++k; if (k >= L) {

delete[] taggedBorder; return j + pos;

}

}

j += i - taggedBorder[i]; if (i == L)

k = std::max(0, k - 1); else if (taggedBorder[i] <= L)

k = std::max(0, taggedBorder[i]), i = L; else

k = L, i = taggedBorder[i];

}

delete[] taggedBorder; return -1;

}

//Knuth-Morris-Pratt search

template <class T = std::string>

int knuthMorrisPrattSearch(const T & str, const T & substr, int pos = 0) { const int n = str.size() - pos, m = substr.size();

if (m == 0) return (n >= 0) ? pos : -1; if (n <= 0 || n < m) return -1;

int * kmpNext = new int[m + 1];

for (int i = 0, j = kmpNext[0] = -1; i < m; ) { while (j > -1 && substr[i] != substr[j])

j = kmpNext[j]; ++i, ++j;

kmpNext[i] = (i < m && substr[i] == substr[j]) ? kmpNext[j] : j;

}

for (int i = 0, j = 0; i < n; ) {

while (j > -1 && substr[j] != str[i + pos]) j = kmpNext[j];

++i;

if (++j < m) continue; delete[] kmpNext; return i - j + pos;

}

delete[] kmpNext; return -1;

}

// Boyer-Moore search

template <class T = std::string>

int boyerMooreSearch(const T & str, const T & substr, int pos = 0) { const int n = str.size() - pos, m = substr.size();

if (m == 0) return (n >= 0) ? pos : -1; if (n <= 0 || n < m) return -1;

int * bG = new int[m], * bB = new int[UCHAR_MAX + 1], * suff = new int[m]; for (int i = 0; i < m; ++i) bG[i] = m;

for (int i = 0; i <= UCHAR_MAX; ++i) bB[i] = m; suff[m - 1] = m;

for (int i = m - 2, g = m - 1, f = 0; i >= 0; --i) if (i > g && suff[i + m - 1 - f] < i - g)

suff[i] = suff[i + m - 1 - f]; else {

if (i < g) g = i; f = i;

while (g >= 0 && substr[g] == substr[g + m - 1 - f]) --g; suff[i] = f - g;

}

for (int i = m - 1, j = 0; i >= 0; --i) if (suff[i] == i + 1)

for (int end = m - 1 - i; j < end; ++j) if (bG[j] == m)

bG[j] = end;

for (int i = 0, end = m - 1; i < end; ++i)

bB[(unsigned char) substr[i]] = bG[end - suff[i]] = end - i;

for (int i, j = 0, end = n - m; j <= end; j += std::max(bG[i], bB[(unsigned char) str[i + j + pos]] + i + 1 - m)) {

for (i = m - 1; i >= 0 && substr[i] == str[i + j + pos]; --i); if (i >= 0) continue;

delete[] bG, delete[] bB, delete[] suff; return j + pos;

}

delete[] bG, delete[] bB, delete[] suff; return -1;

}

// Turbo-Boyer-Moore search template <class T = std::string>

int turboBoyerMooreSearch(const T & str, const T & substr, int pos = 0) { const int n = str.size() - pos, m = substr.size();

if (m == 0) return (n >= 0) ? pos : -1; if (n <= 0 || n < m) return -1;

int * bG = new int[m], * bB = new int[UCHAR_MAX + 1], * suff = new int[m]; for (int i = 0; i < m; ++i) bG[i] = m;

for (int i = 0; i <= UCHAR_MAX; ++i) bB[i] = m; suff[m - 1] = m;

for (int i = m - 2, g = m - 1, f = 0; i >= 0; --i) if (i > g && suff[i + m - 1 - f] < i - g)

suff[i] = suff[i + m - 1 - f]; else {

if (i < g) g = i; f = i;

while (g >= 0 && substr[g] == substr[g + m - 1 - f]) --g; suff[i] = f - g;

}

for (int i = m - 1; i >= 0; --i) if (suff[i] == i + 1)

for (int j = 0, end = m - i - 1; j < end; ++j) if (bG[j] == m)

bG[j] = end;

for (int i = 0, end = m - 1; i < end; ++i)

bB[int((unsigned char) substr[i])] = bG[end - suff[i]] = end - i; for (int j = 0, u = 0, shift = m, end = n - m; j <= end; j += shift) {

int i = m - 1;

while (i >= 0 && substr[i] == str[i + j + pos]) { --i;

if (u != 0 && i == m - 1 - shift) i -= u;

}

if (i < 0) {

delete[] bG, delete[] bB, delete[] suff; return j + pos;

}

int v = m - 1 - i, tShift = u - v, bcShift = bB[int((unsigned char) str[i + j + pos])] -

m + 1 + i;

shift = std::max({ tShift, bcShift, bG[i] }); if (shift == bG[i])

u= std::min(m - shift, v); else {

if (tShift < bcShift)

shift = std::max(shift, u + 1);

u= 0;

}

}

delete[] bG, delete[] bB, delete[] suff; return -1;

}

// Colussi search

template <class T = std::string>

int colussiSearch(const T & str, const T & substr, int pos = 0) noexcept(false) { const int n = str.size() - pos, m = substr.size();

if (m == 0) return (n >= 0) ? pos : -1; if (n <= 0 || n < m) return -1;

int * h = new int[m], * next = new int[m + 1], * shift = new int[m + 1], * hmax = new int[m + 1],

* kmin = new int[m] {0}, * nhd0 = new int[m], * rmin = new int[m]; for (int i = 1, k = 1; k <= m; ) {

while (i < m && substr[i] == substr[i - k]) ++i; hmax[k] = i;

int q = k + 1;

while (hmax[q - k] + k < i) hmax[q] = hmax[q - k] + k, ++q;

k = q;

if (k == i + 1) i = k;

}

for (int i = m; i > 0; --i) if (hmax[i] < m)

kmin[hmax[i]] = i;

for (int i = m - 1, r = 0; i >= 0; --i) { if (hmax[i + 1] == m) r = i + 1; rmin[i] = (kmin[i] == 0) ? r : 0;

}

int s = -1;

for (int i = 0, r = m; i < m; ++i) h[((kmin[i] == 0) ? --r : ++s)] = i;

int nd = s;

for (int i = 0; i <= nd; ++i) shift[i] = kmin[h[i]];

for (int i = nd + 1; i < m; ++i) shift[i] = rmin[h[i]];

shift[m] = rmin[0]; s = 0;

for (int i = 0; i < m; ++i) { nhd0[i] = s;

if (kmin[i] > 0) ++s;

}

for (int i = 0; i <= nd; ++i) next[i] = nhd0[h[i] - kmin[h[i]]];

for (int i = nd + 1; i < m; ++i) next[i] = nhd0[m - rmin[h[i]]];

next[m] = nhd0[m - rmin[h[m - 1]]];

for (int i = 0, j = 0, last = -1, end = n - m; j <= end; j += shift[i], i = next[i]) { while (i < m && last < j + h[i] && substr[h[i]] == str[j + h[i] + pos]) ++i; if (i < m && last < j + h[i]) {

if (i > nd) last = j + m - 1; continue;

}

delete[] h, delete[] next, delete[] shift, delete[] hmax, delete[] kmin, delete[] nhd0, delete[] rmin;

return j + pos;

}

delete[] h, delete[] next, delete[] shift, delete[] hmax, delete[] kmin, delete[] nhd0, delete[] rmin;

return -1;

}

Пройденное тестирование:

1.Пустая строка («» в «» с индекса 0 встречается, «» в «» с индекса 1 не встречается, то есть результат равен -1; также непустые подстроки; где «» – это пустая строка).

2.Строка с одним символом («» в «1» с индекса 0 встречается, «» в «1» с индекса 1 тоже встречается, а с индекса 2 не встречается; также непустые подстроки).

3.Длинная строка с единственным уникальным элементом (если подстрокой является сама строка и поиск осуществляется с индекса 0, то результирующий индекс 0, иначе -1).

4.Простая строка (поиск префиксов и суффиксов в простой строке; также поиск подстрок длиной 2, реверсивных [обратных] подстрокам исходной строки).

5.Простые тесты. Одна строка на все простые тесты, а поиск с разных позиций.

6.Сложные тесты. Генерация новой строки раз в 50 итераций, поиск с разных позиций.

7.На время. 1) Короткие строки, короткие подстроки; 2) Короткие строки, длинные подстроки; 3) Длинные строки, короткие подстроки; 4) Длинные строки, длинные подстроки. Также важен размер используемого алфавита (например, 62, 90 и 230 символов).

Проверка осуществляется сравнением подстроки с результативного индекса (длиной исходной подстроки) и подстроки с результативного индекса (длиной исходной подстроки) стандартного поиска C++ std::find.