Поиск подстроки в строке по алгоритму Кнута-Морриса-Пратта
Поиск подстроки в строке по алгоритму Кнута-Морриса-Пратта
Алгоритм Кнута-Морриса-Пратта, он же классический "КМП-алгоритм" - один из самых эффективных алгоритмов поиска подстроки в строке. Оптимизация достигается за счет того, что при возникновении несоответствия само искомое слово содержит достаточно информации, чтобы определить, где может начаться следующее совпадение, минуя лишние проверки. Скорость работы алгоритма линейно зависит от объема входных данных, то есть невозможно разработать более эффективный алгоритм с точки зрения вычислительной сложности.
Единственным недостатком КМП-алгоритма можно отнести необходимость выделения памяти под таблицу префиксов-суффиксов максимальной длины, ну и предварительное заполнение этой таблицы. В остальном алгоритм крайне эффективен.
Code (Assembler) : Убрать нумерацию
- ;----------------------------------------------------------------------
- ; Функция поиска подстроки в строке по алгоритму Кнута-Морриса-Пратта
- ; by ManHunter / PCL (www.manhunter.ru)
- ;----------------------------------------------------------------------
- ; Параметры:
- ; lpHaystack - указатель на исходную строку
- ; dHLen - длина исходной строки
- ; lpNeedle - указатель на строку для поиска
- ; dNLen - длина строки для поиска
- ; На выходе:
- ; EAX = позиция подстроки в строке
- ; EAX = -1 если подстрока не найдена
- ;----------------------------------------------------------------------
- proc kmp_search lpHaystack:DWORD,dHLen:DWORD,lpNeedle:DWORD,dNLen:DWORD
- locals
- hMem dd ?
- endl
- pusha
- ; Искомая строка длиннее области поиска?
- mov eax,[dHLen]
- cmp eax,[dNLen]
- jb .loc_error
- ; Строки не могут быть пустыми
- cmp [dHLen],0
- je .loc_error
- cmp [dNLen],0
- je .loc_error
- ; Выделить память под массив префиксов-суффиксов
- mov eax,[dNLen]
- shl eax,2
- invoke GlobalAlloc,GMEM_MOVEABLE+GMEM_ZEROINIT,eax
- mov [hMem],eax
- invoke GlobalLock,[hMem]
- mov ebx,eax
- mov edx,[lpNeedle]
- xor edi,edi
- mov [ebx],edi
- mov esi,1
- .loc_pre:
- cmp esi,[dNLen]
- jae .loc_pre_done
- mov al,byte[edx+esi]
- cmp al,byte[edx+edi]
- jne @f
- inc edi
- mov dword[ebx+esi*4],edi
- inc esi
- jmp .loc_pre
- @@:
- cmp edi,0
- jne @f
- mov dword[ebx+esi*4],0
- inc esi
- jmp .loc_pre
- @@:
- mov edi,dword[ebx+edi*4-4]
- jmp .loc_pre
- .loc_pre_done:
- xor esi,esi
- xor edi,edi
- .loc_search:
- cmp esi,[dHLen]
- jae .loc_search_done
- mov edx,[lpHaystack]
- mov al,byte[edx+esi]
- mov edx,[lpNeedle]
- cmp al,byte[edx+edi]
- jne @f
- inc esi
- inc edi
- @@:
- cmp edi,[dNLen]
- jne @f
- mov ebx,esi
- sub ebx,[dNLen]
- jmp .loc_clear
- @@:
- cmp esi,[dHLen]
- jae .loc_search
- mov edx,[lpHaystack]
- mov al,byte[edx+esi]
- mov edx,[lpNeedle]
- cmp al,byte[edx+edi]
- je .loc_search
- cmp edi,0
- jne @f
- inc esi
- jmp .loc_search
- @@:
- mov edi,dword[ebx+edi*4-4]
- jmp .loc_search
- .loc_search_done:
- ; Подстрока не найдена
- mov ebx,-1
- .loc_clear:
- ; Прибраться за собой
- invoke GlobalUnlock,[hMem]
- jmp .loc_done
- .loc_error:
- ; Подстрока не может быть найдена
- mov ebx,-1
- .loc_done:
- ; Результат в EAX
- mov [esp+28],ebx
- popa
- ret
- endp
В приложении пример программы с исходным текстом, которая ищет подстроку в строке по алгоритму Кнута-Морриса-Пратта.
Просмотров: 427 | Комментариев: 1
Метки: Assembler, полезные функции
Комментарии
Отзывы посетителей сайта о статье
user
(15.06.2024 в 08:13):
У меня при парсинге больших файлов профайлер показывает проседание именно на простой функции поиска подстроки (либа самописная). Так что да, это достаточно важная оптимизация.
Добавить комментарий
Заполните форму для добавления комментария