ИНФОРМАТИКА, ВЫЧИСЛИТЕЛЬНАЯ
ТЕХНИКА И УПРАВЛЕНИЕ INFORMATION TECHNOLOGY, COMPUTER SCIENCE, AND MANAGEMENT
УДК 519.689 https://doi.org/10.23947/1992-5980-2019-19-3-290-300
Ускоренный препроцессинг в задаче поиска подстрок в строке*
А. В. Мазуренко1, Н. В. Болдырихин2
1 ООО «ДДОС-Гвард», г. Ростов-на-Дону, Российская Федерация
2 Донской государственный технический университет, г. Ростов-на-Дону, Российская Федерация Accelerated preprocessing in task of searching substrings in a string ***
A. V. Mazurenko1, N. V. Boldyrikhin2**
1 DDoS-GUARD LLC, Rostov-on-Don, Russian Federation
2 Don State Technical University, Rostov-on-Don, Russian Federation
Введение. Бурное развитие таких систем, как Yandex, Google и пр., предопределило актуальность задачи поиска подстрок в строке. На сегодняшний день активно исследуются подходы к ее решению. Эта задача используется при создании систем управления базами данных, поддерживающих ассоциативный поиск. Кроме того, она применима при решении вопросов информационной безопасности, создании антивирусных программ. Алгоритмы поиска подстрок в строке используются в задачах обнаружения, основанного на сигнатурах.
Материалы и методы. Решение задачи базируется на алгоритме Ахо — Корасик, который представляет собой классический способ осуществления поиска подстрок в строке. Вместе с тем применен новый подход в части, касающейся предварительной обработки. Результаты исследования. Показана возможность построения функции перехода и суффиксных ссылок при помощи суффиксных массивов и специальных отображений. Исследована взаимосвязь между префиксным деревом и суффиксными массивами. Это дало возможность разработать принципиально новый способ построения функций перехода и ошибок.
Полученные результаты позволяют существенно сократить время, затрачиваемое на предвыборную обработку множества строк образцов при использовании целочисленного алфавита.
В статье приведено восемь алгоритмов. Оценены разработанные алгоритмы. Полученные результаты сопоставлены g с ранее известными. Доказаны две теоремы и восемь
лемм. Приведены два примера, иллюстрирующие особен-д ности практического применения разработанной процеду-
-§ ры препроцессинга.
Обсуждение и заключения. Предложенная в данной статье J3 процедура препроцессинга основывается на связи между
сл
¡и суффиксным массивом, созданным на основе множества
строк образцов, и построением функций перехода и ошибок на начальных этапах работы алгоритма Ахо — Корасик. Такой подход отличен от традиционного и требует
Л £ Л
* Работа выполнена в рамках инициативной НИР.
290 Е-mail: [email protected], [email protected]
*** The research is done within the frame of the independent R&D.
Introduction. A rapid development of the systems such as Yandex, Google, etc., has predetermined the relevance of the task of searching substrings in a string, and approaches to its solution are actively investigated. This task is used to create database management systems that support associative search. Besides, it is applicable in solving information security issues and creating antivirus programs. Algorithms of searching substring in a string are used in signature-based discovery tasks. Materials and Methods. The solution to the problem is based on the Aho-Corasick algorithm which is a typical technique of searching substrings in a string. At the same time, a new approach regarding preprocessing is employed. Research Results. The possibility of constructing the transition function and suffix references through suffix arrays and special mappings, is shown. The relationship between the prefix tree and suffix arrays was investigated, which provided the development of a fundamentally new method of constructing the transition and error functions. The results obtained enable to substantially shorten the time intervals spent on the preelection processing of a set of pattern strings when using an integer alphabet. The paper lists eight algorithms. The developed algorithms are evaluated. The results obtained are compared to the formerly known. Two theorems and eight lemmas are proved. Two examples illustrating features of the practical application of the developed preprocessing procedure are given.
Discussion and Conclusions. The preprocessing procedure proposed in this paper is based on the communication between the suffix array built on the ground of a set of pattern strings and the construction of transition and error functions at the initial stages of the Aho-Corasick algorithm. This approach differs from the traditional one and requires the use of algo-
использования алгоритмов, позволяющих построить суф-фиксный массив за линейное время. Таким образом, описаны алгоритмы, позволяющие существенно сократить время на предварительную обработку множества строк образцов при условии использования определенного типа алфавита по сравнению с известным подходом, предложенным А. Ахо и М. Корасик.
Результаты исследований, приведенные в статье, могут быть применены в антивирусных программах, использующих поиск сигнатур вредоносных информационных объектов в памяти вычислительной системы. Кроме того, данный подход к решению задачи поиска подстроки в строке позволяет значительно ускорить работу систем управления баз данных, применяющих ассоциативный поиск.
rithms providing a suffix array in linear time. Thus, the algorithms that enable to significantly reduce the time for preprocessing of a set of pattern strings under the condition of using a certain type of alphabet in comparison to the known approach proposed in the Aho- Corasick algorithm are described. The research results presented in the paper can be used in antivirus programs that apply searching for signatures of malicious data objects in the memory of a computer system. In addition, this approach to solving the problem on searching substrings in a string will significantly speed up the operation of database management systems using associative search.
Ключевые слова: поиск подстроки, алгоритм Ахо — Корасик, префиксное дерево, суффиксный массив, поиск информации, функция ошибок, функция перехода.
Образец для цитирования: Мазуренко, А. В. Ускоренный препроцессинг в задаче поиска подстрок в строке / А. В. Мазуренко Н. В. Болдырихин // Вест- ник Дон. гос. техн. ун-та. — 2019. — Т. 19, № 3. — С. 290-300. https://doi.org/ 10.23947/1992-5980-2019-19-3- 290-300
Keywords: string searching, Aho-Corasick algorithm, prefix tree, suffix array, information search, error function, transition function
For citation: A.V. Mazurenko, N.V.Boldyrikhin. Accelerated preprocessing in task of searching substrings in a string. Vest-nik of DSTU, 2019, vol. 19, no. 3, pp. 290-300. https://doi.org/10.23947/1992-5980-2019-19-3-290-300
Введение. В настоящее время существенно возрастает важность обеспечения кибербезопасности рас-пределонных информационных систем и отдельных вычислительных средств [1]. Диапазон таких задач достаточно широк [1-10]. Особое место занимают вопросы создания эффективного антивирусного программного обеспечения (ПО). Одной из важнейших задач, решаемых таким ПО, является поиск подстрок в строке [1, 5, 6, 10-13].
Материалы и методы. Задача поиска подстрок заключается в нахождении всех строк в тексте Т общей длиной т, совпадающих с каким-либо образцом из заданного множества образцов Р. Положим, сумма длин всех элементов Р, состоящих из символов алфавита I, равна п. Решение этой задачи было предложено А. Ахо и
М. Корасик [6, 10]. В их алгоритме время предвыборной обработки составляет п|/|), а время поиска — и
К
т|/| + к) . Здесь к — количество совпадений, найденных в тексте со строками, принадлежащими множеству «
образцов. <з
В настоящее время задача поиска подстроки в строке активно исследуется по двум причинам: К
— поисковые системы активно развиваются [11]; к
— процесс обнаружения в антивирусных программных продуктах основывается на сигнатурах [1].
К
В этой связи были созданы алгоритмы, которые приходится выбирать в зависимости от определенных щ
X
потребностей пользователя. Новейшие результаты, полученные при решении задачи поиска множества под- <р строк, описаны в работе [13]. к:
ей
Представленные в данной статье результаты основываются на связи между суффиксным массивом, созданным на основе множества строк образцов, и построением функций перехода и ошибок на начальных этапах § работы алгоритма Ахо — Корасик. Такой подход отличен от традиционного и требует использования алгоритмов, позволяющих построить суффиксный массив за линейное время. Итак, в статье описаны алгоритмы, с по- Ц
к
ю
мощью которых время выполнения предвыборной обработки сокращается до O (n).
Пусть задан алфавит I, множество образцов P = {Pi,P>,...Pk}, где Pi е I*, i = 1, к . Обозначим через <з
к s
n k \Pi |. Будем считать, что алфавит I представляет собой ограниченный промежуток целых чисел. Грани- fe
i=1 о,
* г -1 О
ца может зависеть от длины рассматриваемой строки s е I либо представлять собой промежуток [0, cj, где c
К
— натуральное число: с > |s|. Пусть е е I — пустая строка. К
Пусть goto — функция перехода, а failure — функция ошибок. Приводимые модификации касаются методов построения упомянутых функций, используемых в алгоритме Ахо — Корасик [6, 10]. 291
Л £ Л
Положим, БиДАгг(5) — некоторый алгоритм построения суффиксного массива для строки 5 е I за
линейное время. Описание таких алгоритмов можно найти, например, в [12-15].
*
Пусть х, у е I . Тогда, 1ср(х, у) — наибольший общий префикс строк х и у.
Рассмотрим строку 5 еI , 5 = 5[я[0]5[1]...5[и-1]]. Пусть 5[ф'М' +1]...5[/]] — подстрока 5, включаю-
щая символы от i до j, где i < j, i, j = 0, n -1. Обозначим через ps суффиксный массив, соответствующий строке s. Пусть
Ps = Ps [ Ps [0] Ps М... Ps [n -1] ] ,
то есть s [s [Ps [0]] ...s [n -1]] < s [s [ps [1]] ...s [n -1]] <... < s [s [ps [n -1]] ...s [n -1]].
Для построения суффиксного массива будет использован алгоритм, описанный в [15].
Положим, ai gI, ai Ф a,j, 1 <i < j <k +1, a1 <a2 <... <ak+\. Пусть Vb eI ai <b , где 1 <i <k +1.
Допустим, что P Ф 0, alPha = {aj ,a2 ,• • -,ak Щ+1}.
Алгоритм обработки суффиксного массива Ps
* *
Здесь s e I : s = a1P1a2P2^akPkak+1, P e I , 1 < i < k . AdaPtation (s, Ps, alPha)
1. newarray ^ e
2. for (i ^ \alPha\;i < |s|;i + +) {
3. j^ 0
4. while (s[s[ps[i]]...s[|s| -1]][j]g alPha) {
5. new array [/][j] ^ s[s[Ps[i]]...s[|s|-1]][j]
6. j ^ j + 1
7. }
8. }
9. orderedlist [0] ^ new array [0]
10. for (i ^1;i < |s| -alPha\;i + +) {
11. j ^ 0
12. if (new _ array [i ] Ф new _ array [i -1]) {
13. ordered list[i] ^ new array [i]
14. j ^j + 1
15. }
16. }
17. return ordered list
Лемма 1. Пусть P = {p,P, ...,Pk}, s = a1P}a2P^-.aak+1. Тогда алгоритм AdaPtation строит массив g лексикографически упорядоченных суффиксов образцов, принадлежащих P, за время O (| s| - \alPha\).
Доказательство. В цикле 2-8 выполняется построение массива new array, i-й элемент которого предо ставляет собой такой префикс соответствующего суффикса s, который включает в себя все символы данного '"О
^ суффикса, начиная с нулевой позиции до его первого элемента, принадлежащего множеству alPha. При этом й при помощи суффиксного массива Ps перебираются все суффиксы s согласно их лексикографическому поряд-
сл
> ку. Таким образом, массив new array состоит из всех суффиксов образцов, принадлежащих P согласно их лексикографическому упорядочиванию, причем возможно повторение некоторых суффиксов. Заметим, что из рассмотрения исключаются все строки, начинающиеся с символов, принадлежащих массиву alPha, то есть первые \alPhd\ суффиксы. Далее в цикле 10-16 при помощи массива new array строится массив ordered list путем исключения повторяющихся строк. Для этого в силу лексикографического порядка следования строк достаточно 292 проверить, совпадает ли рассматриваемая строка с предыдущей.
Цикл 2-8 выполняется за время O(|s| -\alpha\), поскольку из рассмотрения исключаются все строки, начинающиеся с символов, принадлежащих массиву alpha. В цикле 10-16 происходит |s| -\alphd\ сравнений строк. Таким образом, получаем асимптотическую оценку времени работы алгоритма O(|s| -\alpha\). Лемма доказана.
Алгоритм разбиения согласно лексикографическому упорядочению
Здесь s — массив лексикографически упорядоченных строк.
DandC ( s)
1. sub [0]^ 0
2. j ^ 0
3.for (i ^0;i <-1;i + +) {
4. if (s[i] Ф s[i +1]) {
5. sub [ j i +1
6. j ^ j +1
7. }
8. sub [ j] ^ |s|
9. return sub
Лемма 2. Алгоритм DandC на основе массива лексикографически упорядоченных строк s строит массив sub, состоящий из целых положительных чисел, указывающих индексы, соответствующие первым строкам среди строк, у которых равны первые символы, за время O (|s|) .
Доказательство. Граница, соответствующая первому символу, начинается с 0, что соответствует присваиванию, выполняемому на шаге 1. В цикле 3-7 последовательно сравниваются первые символы i-й и (i + 1)-
й строк, где i = 0, |s| - 2. Если символы не равны, то в массив sub записывается начало границы, соответствующей следующему символу. В противном случае выполнение цикла продолжается. Правая граница последнего символа соответствует количеству строк в массиве s (шаг 8).
Сравнение на шаге 4 происходит за время O (1), как и запись на шаге 5 и инкрементирование на ша-
<и
ге 6. Таким образом, цикл 3-7 выполняется за время O (|s|) . Лемма доказана. щ
Алгоритм построения первой связи ю
* ^
Здесь tree — дерево, lex _ words е I , link _ num — номер некоторого символа строки lex _ words, v — к порядковый номер нового узла, который присоединяется к узлу с порядковым номером node _ number . IS
<3
к
3. new tree.node [node _number] .link^ tree.node [v] ч
H
о
5. v ^ v +1 g
У
Лемма 3. Алгоритм BuildFirstLink осуществляет построение нового узла с порядковым номером v и ду- 2 ги, ведущей от узла nodenumber к новому узлу v, в дереве tree за время O (1).
Алгоритм построения связи с подстрокой н
сЗ
* S
Здесь tree — дерево, lex _ words е I , v — порядковый номер нового узла, который присоединяется к ^
о
узлу с порядковым номером start.
X
BuildSubstringLink (tree&, lex _ words &, v&, start) К
BuildFirstLink (tree&, lex _ words&, v&, link _ num, node _ number)
1. new tree.node [v]
2. tree.node [v] .state ^ lex_words[lex_words[0]...lex_words[link]]
4. tree.node [node _number] .link.symbol^ lex_words[link_num]
1. for (k ^ start; k < |/ex _ words\; k + +) {
Ö О T3
M
"c
и (U
Ü С Л
2. new tree.node [v]
3. tree.node [v] .state ^ lex_words [lex_ words[0]...lex_ words[k]]
4. new tree.node [v -1] .link^ tree.node [v]
5. tree.node [v-1] .link.symbol^ lexwords [k]
6. v ^ v +1
7. }
Лемма 4. Алгоритм BuildSubstringLink осуществляет построение новых узлов в дереве tree, соответствующих всем префиксам строки lex_words, начиная с префикса lex _ words [lex _ words [0]...lex _ words[start]]
за время O (I lex _ words\ - start) .
Алгоритм построения последней связи
*
Здесь tree — дерево, lex _ words е I , v — порядковый номер новой дуги, I — алфавит.
BuildLastLink (tree&, lex _ words, v, I)
1. new tree.node [0] .link[v] ^ tree.node [0]
2. symbols ^ 0
3. for (i ^0;i < |lex_words\;i + +) {
4. symbols [i\ ^ lex_words [i\[0\
5. j^ 0
6. for (i ^0;i <|I|;i + +) {
7. if (I[i] g symbols) {
8. tree.node [0] .link[v] .symbol[ j] ^ I[i]
9. j ^ j +1
10. } 11. }
Лемма 5. Алгоритм BuildLastLink строит при корневом узле петлю. Ее пометка соответствует множеству символов, по которым невозможно перейти в другие узлы дерева tree из корневого узла за время O (|lex _ words\ + |I|) .
Алгоритм построения переходов
Здесь lex _ words — массив лексикографически упорядоченных строк.
CreateLink (lex _ words )
1. str ^ 0
2. sub ^ DandC (lex _ words)
3. v ^ 1
4. tree ^ 0
5. tree.node [0] .state ^ e
6. for (i ^0;i < |sub| -1;i + +) {
7. BuildFirstLink (tree, lex _ words [sub[i]], v, 0,0)
8. BuildSubstringLink (tree, lex _ words [sub[i]], v,1)
9. for (j ^ sub[i] + 1; j < sub[i + 1]; j + +) {
10. temp ^ |lcp (lex _ words[j -1], lex _ words[j ])| +1
11. z ^ tree.getStateNumber(lcp (lex _ words[j -1], lex _ words[j]))
12. BuildFirstLink (tree, lex _ words[ j], v, temp, z)
13. BuildSubstringLink (tree, lex _ words [ j ], v, temp )
14. }
15. }
16. BuildLastLink (tree, lex _ words, v, lex _ words)
17. return tree
Лемма 6. Алгоритм CreateLink осуществляет построение префиксного дерева tree с петлей при корне-
1 |lex _ words |—1.
I |/ex _ words|—I. .
вом узле за время OI ^ \lex _ words[i]| .
Доказательство. На шаге 2 выполняется алгоритм DandC (см. лемму 2), после чего на шаге 5 создается корневой узел с порядковым номером 0 дерева tree. Его состояние полагается равным пустой строке е. Рассмотрим цикл 6-I5 на i-м шаге работы.
На шаге 7 при помощи алгоритма BuildFirstLink создается узел, состояние которого соответствуют первому символу строки lex_ words [sub[i]]. Учитывая построение массива sub, можно утверждать, что такой символ прежде не встречался среди первых символов предыдущих строк. Тогда на шаге 8 реализация алгоритма BuildSubstringLink последовательно создает узлы, состояние которых соответствует всем префиксам строки lex _ words [sub[i]], исключая префикс, построенный в предшествующей строке.
В цикле 9-I4 при помощи алгоритмов BuildFirstLink и BuildSubstringLink выполняем те же действия со строками, лежащими в целочисленном промежутке [sub[i] +1, sub[i +1] — I]. Поскольку у каждой такой строки
есть общий ненулевой префикс с предыдущей строкой, то алгоритм немедленно переходит в состояние, соответствующее наибольшему общему префиксу, начиная с которого необходимо строить новые узлы. На шаге I6 при помощи алгоритма BuildLastLink создается петля при корневом узле. Шаги I2 и 13 выполняются за время
O (I) + O (| lex _ words [ j ]| — |lcp (lex _ words [ j — I], lex _ words [ j ])| — i) =
= O (| lex _ words [ j I -|lcp (lex _ words [ j — I], lex _ words [ j ])|) . Таким образом, из лемм 2, 3 и 4 следует, что цикл 9-14 выполняется за время
OI| ' [ +i] ^|lex_words[j]| — |lcp(lex_words[j — I],lex_words[j])||j.
к
Цикл 6-14 выполняется за время
OI I ' ■ b Ilex _ words[sub[i]]| | +
+OI | '\ j | ' [+] |lex_words[j]|— |lcp(lex_words[j — I],lex_words[j])| 1 = ^
v / ^
К
= O II"
|lex_words[sub[i]]— |lex_words\ I. g
^lex _ words |—I.
ConstructGoto (P) L s^ aIPIa2P2■ ■ ■akPkak+I
ffl cö
a с
I . . % ^ |/ex _ words|—1. - j Й
Из леммы 5 следует, что шаг 16 выполняется за время O\\lex_words\ + > \lex_words[i] I. ^
^ 1 1 s
Таким образом, получаем асимптотическую оценку времени работы алгоритма К
|sub|—___,, .Л
£
O(|lex _words\) + O^ ^ |lex_words [sMb[/]| -\lex _words\
j . . k i ^ex _ words|—1. Til I |le-x _ words|—1. . j ^
O jjlex _ words\ + | lex _ words ['J|l = O j ^^. |lex _ words [z'| I. ^
¿=0 1 _ L -" I IZ—(i=0 I - L Ji I
1 v 1
Лемма доказана. S
л
Алгоритм построения функции goto о
IQ
Здесь P — множество строк образцов. щ
S
Ö О 43
M
'S3
СЛ
<U
Ü £ л
2. ps ^ SuffArr(s)
3. alpha ^{aj ,a2 ,...,ak ,a¿
4. orderedlist ^ Adaptation {s, ps, alpha)
5. j ^ 0
6. lex_words ^ 0
7. P_length Pi|, IP2I.....IPk 1}
8. for {i ^ 0;i < \ordered _list\;i + +)
9. if {(|ordered_list[i]| e P_length) and (ordered_list[i] e P))
10. lex_words[j + +] ^ ordered_list[i]
11. goto ^ CreateLink (lex _ words)
12. return goto
Напомним, что n . для множества образцов P = {P,P,...,Pk}. Теорема 1. Алгоритм ConstructGoto строит функцию goto за время O {n).
Доказательство. На шаге 2 строится суффиксный массив ps для строки s. На шаге 4 при помощи алгоритма Adaptation в массив ordered list записываются все суффиксы строк, принадлежащих множеству образцов P. При этом не исключены повторения. В цикле 8-10 строится массив lexwords, содержащий суффиксы, принадлежащие P, расположенные в лексикографическом порядке без повторений. На шаге 11 происходит построение префиксного дерева с петлей при корневом узле на основе строк, которые содержатся в массиве lex_words. Структура данных, возвращаемая алгоритмом CreateLink, в точности задает функцию goto.
Шаг 2 выполняется за время O{n + k +1) [12]. Из леммы 1 следует, что шаг 4 выполняется за время
O {n + k +1 - k - l) = O {n) . В цикле 8-10 рассматриваются только строки, длина которых равна длине какого-либо образца.
Таким образом, потребуется не более O {n) проверок для нахождения образцов P. Из леммы 6 следует,
i|lex _ words |—1. Н=0
ческую оценку времени работы алгоритма O {n) + O {n + k +1) = O {n). Теорема доказана.
Результаты исследования
Пример 1.
Пусть P = {one, on, once, cell, lull, eye, near}. Тогда
s = a]_onea2ona3oncea4cella5,lulla6eyea7neara%. (1)
В табл. 1 представлен результат работы алгоритма построения функции goto при поступлении на вход строки s (1).
Таблица 1
Структура префиксного дерева
что шаг 11 выполняется за время OI ^^
|lex _ woras[i]| = O {n). Так как k < n , получаем асимптоти-
Номер node Состояние node Состояния, в которые ведут ветви link от node Символы на ветвях link от node
0 е 1. c; 2. e; 3. l; 4. n; 5. o 1. c; 2. e; 3. l; 4. n; 5. o
1 c 1. ce 1. e
2 ce 1. cel 1. l
3 cel 1. cell 1. l
4 cell - -
5 e 1. ey 1. У
6 ey 1. eye 1. e
7 eye - -
8 l 1. lu 1. u
Номер node Состояние node Состояния, в которые ведут ветви link от node Символы на ветвях link от node
9 lu 1. lul 1. l
10 lul 1. lull 1. l
11 lull - -
12 n 1. ne 1. e
13 ne 1. nea 1. a
14 nea 1. near 1. r
15 near - -
16 o 1. on 1. n
17 on 1. onc; 2. one 1. c; 2. e
18 onc 1. once 1. e
19 once - -
20 one - -
Пусть s = «/i+|Pkuk... Cb/i«!p()a() — зеркальное отражение строки s. Алгоритм построения функции ошибок failure Здесь P — множество строк образцов.
FalseSuff ( P )
1. s<^ak+lPkak....аз^а^оОо
2. p~s <— SuffArr{s)
3. alpha — {а ,...,Kk ,Ot+1}
4. orderedlist <— Adaptation (.v.p-, alpha)
5. link — 0
6. for (/0;/<|s|;/ + +)
7. inLink [i] — e
8. sub — DandC (ordered _ list)
9. str — 0 К
IB
10. for (i — 0; i < I sub _ 1; i + +) ^
a
с
^
12. str [j] ^ \lcp(ordered _list[j],ordered _list[j +1]) К
ей
13. for (i — 0; i < I sub "1; i + +) s
<a
h «
ей К Л
4
<U h
5
о s t£ S и
ей
и s
ей
11. for (j ^sub[i]; j <sub[i + 1]-1; j + +)
14. for (k — sub[i + 1]-1;k > sub[i];k--) {
15. for (j — sub[i]; j < k; j + +)
16. minelement — min (str[k -1], str[k - 2],..., str [ j])
17. if (min_ element = |ordered _ list[j ]|)
18. min_temp[j -sub[i]] — min element
19. }
20. max element — max (min _ temp[0], min _ temp[1],..., min _ temp[w])
21. найти max index: min_ temp [max_index]= max_element
22. inLink [k ] — ordered _ list [max_ index + sub[i]]
К
24. for (i — 0;i < \inLink\;i + +) {
<a
£ л
25. link[i][0] ^ ordered_list[i] ; //зеркальное отражение строки
26. link[i][1] ^ inLink[i]~ ; //зеркальное отражение строки
27. }
28. return link
Замечание. В строке 20 w < sub[i +1] - sub[i] -1.
Теорема 2. Алгоритм FalseSuff строит функцию ошибок failure за время O(n) . Доказательство. На шаге 1 строим массив символов, содержащий зеркальные отображения строк, принадлежащих множеству образцов Р. и некоторые уникальные символы. На шаге 2 строим суффиксный массив р~ для строки л . На шаге 4 при помощи алгоритма Adaptation в массив ordered list записываются все суффиксы строк, принадлежащих
множеству образцов Р (множество образцов, состоящее из зеркально отраженных строк 1'). при этом не исключены повторения. На шаге 8 выполняется алгоритм DandC (см. лемму 2), после чего в цикле 10-12 находим длину наибольшего общего префикса между строками, у которых совпадает первый символ. Записываем результат в массив str. Заметим, что эта величина равна нулю у строк, для которых данное условие не выполняется. В цикле 13-23 строится специальное отображение между строками, у которых совпадает первый символ. Опишем это отображение. Зафиксируем некоторую строку
s е ordered _ list [iordered _ list [sub[i]],..., ordered _list [sub[i +1] -1]] . Рассмотрим множество, состоящее из строк, принадлежащих
ordered_list[ordered_list[swb[i]],...,ordered_list[sub[i +1]-1]] . Их длина равна длине наибольшего общего
префикса с s, исключая само s. Из этого множества найдем строку s', которая имеет наибольшую длину, и поставим ее в соответствие s. Очевидно, что построенное отображение является биекцией при условии s' Ф е . Полученный результат записывается в массив inLink. В цикле 24-27 при помощи массива inLink явно указываем построенное отображение, при этом зеркально отражая каждую из строк. Таким образом, ставим узлу s префиксного дерева, построенного на основе массива образцов Р, в соответствие узел s'. Его состояние равно наибольшему собственному суффиксу s , который встречается среди множества состояний рассматриваемого префиксного дерева. Но согласно определению функции ошибок failure это и есть искомый результат.
Пусть n . . Шаг 2 выполняется за время O(n + k +1) [12]. Из леммы 1 следует, что шаг 4 выполняется за время О(н + k +1 - к -1) = О (//). Цикл 6-7 выполняется за время 0(|.v|) = О (п). Из леммы 2 следует, что шаг 8 выполняется за время O (n). Цикл 10-12 выполняется за время
ub|-2 sub[i+1]-1 ub[i]+1
1 sub[i+1]—1 k-1 А ( -^-Л sub[i+1]-sub[i]-2
% ^ |sub| 2 V ^ sub[l +1]-1
O ^^ о ^^ ъ[ ] j l = O (k) ' У Y j= 1. Цикл 14-23 выполняется за время
, х—у subi г+11—1 х—^ k -1 \ / х—у subi г+11—subi il-2 \
O| Sk^Sk-sub[i] Y jj= O (S ^ j O (sub[ii +1] - sum -1) , yj Y j = 1.
Тогда цикл 13-23 выполняется за время
|sub|-2 ü=0
O i S 2 (sub[i +1] - sub[i] -1) j = O (sub [|sub\ - i]) = O (k).
Поскольку \тЬтк\ < п, то цикл 24-27 выполняется за время О (| 1пЬтк\) = О (п). Итак, учитывая, что к < п , получаем асимптотическую оценку времени работы алгоритма О (п) + О (п + к +1) + О (к) = О (п) . Тео-
с
о
тз рема доказана. г^ Пример 2.
Пусть, как и в примере 1, P = {one, on, once, cell, lull, eye, near}. Тогда
s = a^raenajeyea6lliila5lleca4ecnoa3noa2enoai. (2)
В табл. 2 представлен результат работы алгоритма построения функции failure при поступлении на вход строки s (2).
Таблица 2
Ложные связи между узлами
Массив inLink Массив link Массив inLink Массив link
0. е 0. 0. ma; 1. е 10. l 10. 0. сеЬ; 1. l
1. е 1. 0. с; 1. е 11. l 11. 0. сеИ; 1. l
2. с 2. 0. one; 1. с 12. l 12. 0. lull; 1. l
3. е 3. 0. е; 1. е 13. l 13. 0. lul; 1. l
4. е 4. 0. се; 1. е 14. е 14. 0. n; 1. е
5. ес 5. 0. оте; 1. се 15. n 15. 0. on; 1. n
6. е 6. 0. w, 1. е 16. е 16. 0. o; 1. е
7. еп 7. 0. от; 1. т 17. е 17. 0. mar; 1. е
8. е 8. 0. еуе; 1. е 18. е 18. 0. lu; 1. е
9. е 9. 0. l; 1. е 19. е 19. 0. еу; 1. е
Для всех узлов, для которых на рис. 1 не указаны ложные связи, полагаем, что ложная связь ведет к корневому узлу.
Рис. 1. Префиксное дерево с ложными связями
Обсуждение и заключения. Описана новая процедура препроцессинга в алгоритме Ахо — Корасик. Она выполняется за линейное время O(n). Исследована связь между суффиксными массивами и префиксным
деревом, что позволило предложить иной способ построения функций перехода и ошибок. Полученные результаты позволяют сократить время на предвыборную обработку множества строк образцов при использовании целочисленного алфавита.
Библиографический список
1. Stallings, W. Computer security: principles and practice / W. Stallings. — Boston : Pearson, 2012. — 182 p.
2. Исследование возможности применения генетических алгоритмов для реализации криптоанализа блочных криптосистем / Ю. О. Чернышев [и др.] // Вестник Дон. гос. техн. ун-та. — 2015. — T. 15, № 3 (82). — С. 65-72.
3. Садовой, Н. Н. Программные утилиты для контроля и предотвращения сетевых атак на уровне доступа к сети / Н. Н. Садовой, Ю. В. Косолапов, В. В. Мкртичян // Вестник Дон. гос. техн. ун-та. — 2005. — Т. 5, № 2 (24). — C. 173-178.
4. Могилевская, Н. С. Пороговое разделение файлов на основе битовых масок: идея и возможное применение / Н. С. Могилевская, Р. В. Кульбикаян, Л. А. Журавлев // Вестник Дон. гос. техн. ун-та. — 2011 — Т. 11, № 10. — С. 1749-1755.
<и S I <и
ю ей
а
с
^
S ей И S I X <и
h «
ей К Л
4 <и h
5
4 о
5 ¡т
S и
ей И S
ей
S а о
-е
к £
5. Шелудько, А. А. Поиск информационных объектов в памяти компьютера при решении задач обеспечения кибербезопасности / А. А. Шелудько, Н. В. Болдырихин // Молодой исследователь Дона. — 2018. — № 6 (15). — С. 81-86.
6. Мазуренко, А. В. Обнаружение, основанное на сигнатурах, с использованием алгоритма Ахо — Ко-расик / А. В. Мазуренко, Н. В. Болдырихин // Тр. Сев.-Кав. ф-ла Моск. техн. ун-та связи и информатики. — 2016. — № 1. — С. 339-344.
7. Мазуренко, А. В. Алгоритм проверки подлинности пользователя, основанный на графических ключах / А. В. Мазуренко, Н. С. Архангельская, Н. В. Болдырихин // Молодой исследователь Дона. — 2016. — № 3 (3). — С. 92-95.
8. Мазуренко, А. В. Геометрическая реализация метода проведения электронных выборов, основанного на пороговом разделении секрета / А. В. Мазуренко, В. А. Стукопин // Вестник Дон. гос. техн. ун-та. — 2018. — Т. 18, № 2. — С. 246-255.
9. Алгоритмическая оценка сложности системы кодирования и защиты информации, основанной на пороговом разделении секрета, на примере системы электронного голосования / Л. В. Черкесова [и др.] // Вестник Дон. гос. техн. ун-та. — 2017. — Т. 17, № 3. — С. 145-155.
10. Антонов, Е. С. Как найти миллион. Сравнение алгоритмов поиска множества подстрок / Е. С. Антонов // RSDN Magazine. — 2011. — № 1. — С. 60-67.
11. Tarakeswar, M. K. Search Engines: A Study / M. K. Tarakeswar, M. D. Kavitha // Journal of Computer Applications. — 2011. — Vol. 4, № 1. — P. 29-33.
12. Karkkainen, J. Linear work suffix array construction / J. Karkkainen, P. Sanders, S. Burkhardt // Journal of the ACM. — 2006. — Vol. 53, № 6. — P. 918-936.
13. Баклановский, М. В. Поведенческая идентификация программ / М. В. Баклановский, А. Р. Ханов // Моделирование и анализ информационных систем. — 2014. — Т. 21, № 6. — С. 120-130.
14. Efficient repeat finding in sets of strings via suffix arrays / V. Becher [et al.] // Discrete Mathematics and Theoretical Computer Science. — 2013. — Vol. 15, № 2. — P. 59-70.
15. Shrestha, A. M. S. A bioinformatician's guide to the forefront of suffix array construction algorithms / A. M. S. Shrestha, M. C. Frith, P. Horton // Briefings in Bioinformatics. — 2014. — Vol. 15, № 2. — P. 138-154.
Сдана в редакцию 22.01.2019 Принята к публикации 12.04.2019
Об авторах:
Мазуренко Александр Вадимович,
математик-программист ООО «ДДОС-Гвард» (РФ, 344002, г. Ростов-на-Дону, пр. Буденновский, 62/2),
ORCID: http://orcid.org/0000-0001-9541-3374
Болдырихин Николай Вячеславович,
доцент кафедры «Кибербезопасность информационных систем» Донского государственного технического университета (РФ, 344000, г. Ростов-на-Дону, пл. Гагарина, 1), кандидат технических наук, ORCID: http://orcid.org/0000-0002-9896-9543, [email protected]
"с
и (U
Ü £ л