Blog. Just Blog

Поиск подстроки в строке по алгоритму Карпа-Рабина

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Поиск подстроки в строке по алгоритму Карпа-Рабина
Поиск подстроки в строке по алгоритму Карпа-Рабина

Когда речь заходит об алгоритмах точного поиска подстроки в строке, то обычно все так или иначе сводится к последовательному сравнению символов. Но есть группа алгоритмов, которые основаны не на сравнении символов, а на сравнении числовых данных - хешей. Одним из таких алгоритмов является алгоритм Карпа-Рабина. Его принцип достаточно простой: вычисляется хеш от строки поиска, затем вычисляется хеш от фрагмента строки, в которой производится поиск. Длина фрагмента равна длине искомой строки. Если хеши равны, то выполняется дополнительное посимвольное сравнение, если не равны, то продвигаемся по строке дальше. Казалось бы, что выигрыша тут никакого быть не может, ведь вместо сравнения вычислительные ресурсы тратятся на хеширование. Однако, как показывает практика, для поиска совпадения это гораздо эффективнее, чем сравнение отдельных символов строк. Вместо O(n*m) операций можно добиться среднего результата O(n+m), где n - длина исходной строки, а m - длина искомой строки. К тому же алгоритм Карпа-Рабина не требует выделения дополнительной памяти для своей работы.

Функция хеширования - очень важная часть алгоритма. Ведь если при ее использовании начнут появляться многочисленные ложные срабатывания, то последующее сравнение символов станет выполняться слишком часто, что сводит на нет всю эффективность алгоритма. Также хеш не должен полностью заново вычисляться для каждого фрагмента, он должен получаться из предыдущего, но при этом соответствовать параметрам поиска. Таким условиям удовлетворяет полиномиальный "скользящий" хеш с операциями сложения и битового сдвига.
  1. ;----------------------------------------------------------------
  2. ; Функция поиска подстроки в строке по алгоритму Карпа-Рабина
  3. ; by ManHunter / PCL (www.manhunter.ru)
  4. ;----------------------------------------------------------------
  5. ; Параметры:
  6. ;   lpHaystack - указатель на исходную строку
  7. ;   dHLen - длина исходной строки
  8. ;   lpNeedle - указатель на строку для поиска
  9. ;   dNLen - длина строки для поиска
  10. ; На выходе:
  11. ;   EAX = позиция подстроки в строке
  12. ;   EAX = -1 если подстрока не найдена
  13. ;----------------------------------------------------------------
  14. proc kr_search lpHaystack:DWORD, dHLen:DWORD, lpNeedle:DWORD, dNLen:DWORD
  15.         pusha
  16.  
  17.         ; Искомая строка длиннее области поиска?
  18.         mov     eax,[dHLen]
  19.         cmp     eax,[dNLen]
  20.         jb      .loc_error
  21.  
  22.         ; Строки не могут быть пустыми
  23.         cmp     [dHLen],0
  24.         je      .loc_error
  25.         cmp     [dNLen],0
  26.         je      .loc_error
  27.         ; Искомая строка не может быть длиннее 32 символов
  28.         cmp     [dNLen],32
  29.         ja      .loc_error
  30.  
  31.         ; Первоначальный расчет хешей
  32.         xor     esi,esi
  33.         xor     edi,edi
  34.         xor