Если кратко, то бор — это один из самых эффективных способов хранения пар «ключ-значение». Чаще всего ключами выступают строки, но в качестве этих ключей можно использовать совершенно любую последовательность байт. Кроме как ассоциативного массива эту структуру можно использовать для установления факта присутствия/отсутствия заданного слова в словаре.
Представляю на суд публике свою реализацию бор'а на чистом Basic'е
Объявления
- Код: Выделить всё
Private Type WORD_NODE
nSibling As Long
fChild As Long
Char As Byte
Last As Byte ' выполняет роль флага о последней букве в слове
' Value as long ' для построения ассоциативного массива
End Type
Private TRIE() As WORD_NODE, ut As Long, nt As Long
Инициализация бор'a
- Код: Выделить всё
ut = 64: nt = 1
ReDim TRIE(ut)
TRIE(0).fChild = 1
TRIE(1).Char = 192 ' А
TRIE(1).Last = 1
Поиск
- Код: Выделить всё
Dim Level As Long
Dim prevFC As Long, FC As Long, WordPresent As Long
Dim inWord() As Byte, inLen As Long, i As Long
Text1.Text = UCase$(Text1.Text)
inLen = Len(Text1.Text)
inWord = StrConv(Text1.Text, vbFromUnicode)
FC = 1
WordPresent = 1
Do
If TRIE(FC).Char = inWord(Level) Then
' дочерний или соседний символ равен входному символу
prevFC = FC
VocPath(Level) = FC
FC = TRIE(FC).fChild
Level = Level + 1
Else
' поиск по соседям
If TRIE(FC).nSibling Then
' у этого уровня есть соседи
FC = TRIE(FC).nSibling
Else
WordPresent = 0
Exit Do
End If
End If
Loop Until Level = inLen
If WordPresent Then
If TRIE(prevFC).Last Then
MsgBox "Слово «" + Text1.Text + "» есть в словаре!", vbExclamation
Else
WordPresent = 0
GoTo 10
End If
Else
10 MsgBox "Слово «" + Text1.Text + "» отсутствует в словаре!", vbCritical
End If
Добавление
- Код: Выделить всё
Private Sub BuildTrie(FindWord As String)
Dim Level As Long
Dim prevFC As Long, FC As Long, fc2 As Long, WordPresent As Long
Dim inWord() As Byte, inLen As Long, i As Long
'Text1.Text = UCase$(Text1.Text)
inLen = Len(FindWord) 'Len(Text1.Text)
inWord = StrConv(FindWord, vbFromUnicode)
FC = 1
WordPresent = 1
Do
If TRIE(FC).Char = inWord(Level) Then
' дочерний или соседний символ равен входному символу
prevFC = FC
VocPath(Level) = FC
FC = TRIE(FC).fChild
Level = Level + 1
Else
' поиск по соседям
If TRIE(FC).nSibling Then
' у этого уровня есть соседи
FC = TRIE(FC).nSibling
Else
WordPresent = 0
Exit Do
End If
End If
Loop Until Level = inLen
fc2 = FC
If WordPresent Then
If TRIE(prevFC).Last Then
Else
WordPresent = 0
GoTo 10
End If
Else
10 ut = ut + (inLen - Level)
ReDim Preserve TRIE(ut)
If Level Then
FC = TRIE(VocPath(Level - 1)).fChild
If FC Then
' у последней совпадающей буквы есть потомок
' проверить на полное совпадение префикса с входным словом
i = 0
Do
If inWord(i) = TRIE(VocPath(i)).Char Then
i = i + 1
Else
Exit Do
End If
Loop Until i = inLen
If i = inLen Then
' самый простой случай добавления -
' префикс полностью существует
FC = VocPath(i - 1)
TRIE(FC).Last = 1
Exit Sub
'GoTo 20
End If
' первый отсутствующий символ префикса является чьим-то соседом
nt = nt + 1
TRIE(fc2).nSibling = nt
For i = Level To inLen - 2
TRIE(nt).Char = inWord(i)
TRIE(nt).fChild = nt + 1
nt = nt + 1
Next
TRIE(nt).Char = inWord(i)
TRIE(nt).Last = 1
Else
' нет потомков
FC = VocPath(Level - 1)
nt = nt + 1
TRIE(FC).fChild = nt
For i = Level To inLen - 2
TRIE(nt).Char = inWord(i)
TRIE(nt).fChild = nt + 1
nt = nt + 1
Next i
TRIE(nt).Char = inWord(i)
TRIE(nt).Last = 1
End If
Else
' нет префикса
' FC - результат основной проверки
nt = nt + 1
TRIE(FC).nSibling = nt
For i = 0 To inLen - 2
TRIE(nt).Char = inWord(i)
nt = nt + 1
TRIE(nt - 1).fChild = nt
Next
' описать последний символ
TRIE(nt).Char = inWord(i)
TRIE(nt).Last = 1
End If
' ' распечатка Бора после добавления
'20 Debug.Print "Last FC =" + Str$(FC)
'
' For i = 1 To nt
' Debug.Print i, _
' Chr$(TRIE(i).Char), _
' Chr$(TRIE(TRIE(i).fChild).Char) + " -" + Str$(TRIE(i).fChild), _
' Chr$(TRIE(TRIE(i).nSibling).Char) + " -" + Str$(TRIE(i).nSibling)
' Next
' Debug.Print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
End If
Да, процедура добавления выглядит громоздко, но лучше я пока не придумал...
Кстати, по смыслу это очень похоже на Хакерское abandonware. Собственно с этого и появился живой интерес к этой проблеме. А недавно для моей программулины понадобился простенький spell checker, что сподвигло к написанию вышеизложенного кода...