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

Поиск подстроки в строке по алгоритму Карпа-Рабина
Когда речь заходит об алгоритмах точного поиска подстроки в строке, то обычно все так или иначе сводится к последовательному сравнению символов. Но есть группа алгоритмов, которые основаны не на сравнении символов, а на сравнении числовых данных - хешей. Одним из таких алгоритмов является алгоритм Карпа-Рабина. Его принцип достаточно простой: вычисляется хеш от строки поиска, затем вычисляется хеш от фрагмента строки, в которой производится поиск. Длина фрагмента равна длине искомой строки. Если хеши равны, то выполняется дополнительное посимвольное сравнение, если не равны, то продвигаемся по строке дальше. Казалось бы, что выигрыша тут никакого быть не может, ведь вместо сравнения вычислительные ресурсы тратятся на хеширование. Однако, как показывает практика, для поиска совпадения это гораздо эффективнее, чем сравнение отдельных символов строк. Вместо O(n*m) операций можно добиться среднего результата O(n+m), где n - длина исходной строки, а m - длина искомой строки. К тому же алгоритм Карпа-Рабина не требует выделения дополнительной памяти для своей работы.
Функция хеширования - очень важная часть алгоритма. Ведь если при ее использовании начнут появляться многочисленные ложные срабатывания, то последующее сравнение символов станет выполняться слишком часто, что сводит на нет всю эффективность алгоритма. Также хеш не должен полностью заново вычисляться для каждого фрагмента, он должен получаться из предыдущего, но при этом соответствовать параметрам поиска. Таким условиям удовлетворяет полиномиальный "скользящий" хеш с операциями сложения и битового сдвига.
Code (Assembler) : Убрать нумерацию
- ;----------------------------------------------------------------
- ; Функция поиска подстроки в строке по алгоритму Карпа-Рабина
- ; by ManHunter / PCL (www.manhunter.ru)
- ;----------------------------------------------------------------
- ; Параметры:
- ; lpHaystack - указатель на исходную строку
- ; dHLen - длина исходной строки
- ; lpNeedle - указатель на строку для поиска
- ; dNLen - длина строки для поиска
- ; На выходе:
- ; EAX = позиция подстроки в строке
- ; EAX = -1 если подстрока не найдена
- ;----------------------------------------------------------------
- proc kr_search lpHaystack:DWORD, dHLen:DWORD, lpNeedle:DWORD, dNLen:DWORD
- pusha
- ; Искомая строка длиннее области поиска?
- mov eax,[dHLen]
- cmp eax,[dNLen]
- jb .loc_error
- ; Строки не могут быть пустыми
- cmp [dHLen],0
- je .loc_error
- cmp [dNLen],0
- je .loc_error
- ; Искомая строка не может быть длиннее 32 символов
- cmp [dNLen],32
- ja .loc_error
- ; Первоначальный расчет хешей
- xor esi,esi
- xor edi,edi
- xor