Изменения

Перейти к: навигация, поиск

Алгоритм МакКрейта

502 байта добавлено, 19:34, 6 мая 2014
Исправлен псевдокод
|id=proposal_invariant
|statement=Инвариант алгоритма сохраняется
|proof=Инвариант мог бы нарушиться только в случае, если бы не существовало вершины в суффиксной ссылке для <tex>head_{i-1}</tex>, но мы продолжили бы сканирование по ребру дальше и получили две вершины <tex>head_{i-1}.suf, \ head_i</tex> с неопределенными суффиксными ссылками. Покажем, что это невозможно. Рассмотрим, что значит, что <tex>head_{i-1}.suf</tex> остановилась посередине ребра. Это означает, что все суффиксы <tex>s[j..n], \ j < i - 1</tex>, которые дошли до этого места, имеют совпадающие следующие символы, по определению <tex>head_{i-1}</tex> отличающиеся от символа суффикса <tex>s[i - 1..n]</tex>. Тогда и <tex>s[i..n]</tex> должен отличаться в этом символе, значит <tex>head_i = head_{i-1}.suf</tex>.
}}
== Псевдокод ==
В вершинах дерева <tex>Node</tex> будем хранить следующую информацию:
* <tex>parent</tex> {{- --}} предок;* <tex>start, \ end</tex> {{--- }} позиции строки, соответствующие ребру до предка; <tex>s[start, end]</tex>* <tex>length</tex> {{--- }} длина ребра до предка* <tex>depth</tex> {{-- -}} глубина вершины в символах;* <tex>suf</tex> {{--- }} суффиксная ссылка;* <tex>children[]</tex> {{--- }} массив детей.
Конструктор будет иметь вид <code>Node(Node parent, '''int''' start, '''int''' end, '''int''' depth)</code>.Пусть глобально известна строка <tex>s</tex> со специальным символом на конце, ее длина <tex>n</tex> и используемый алфавит <tex>\Sigma</tex>.
<code>
'''string''' s '''int''' n = s.length  Node buildSuffixTree():
superRoot = Node('''null''', 0, -1, 0)
superRoot.suf = superRoot
root = Node(superRoot, 0, -1, 0)
root.suf = superRoot
'''for''' c '''in''' <tex>\Sigma</tex>:
superRoot.children[c] = root
head = root
'''for''' i = 1 '''to''' n:
head = addSuffix(head, i)
'''return''' root
Node addSuffix(Node head, '''int''' start):
newHead = slowScan(fastScan(head), start)
newLeaf = Node(newHead, start + newHead.depth, n, n - start + 1)
'''return''' newHead
Node fastScan(Node head): '''if''' head.depth == 0: '''return''' head '''if''' head.suf == '''null''':
skipped = head.length
curPos = head.start
'''if''' skipped > 0 '''and''' head.parent.depth == 0:
skipped--
curPos++
curNode = head.parent.suf
'''while''' curNode.children[s[curPos]].length <tex>\leqslant</tex>= skipped:
curNode = curNode.children[s[curPos]]
skipped -= curNode.length
curPos += curNode.length
'''if''' skipped > 0:
newNode = split(curNode, curNode.children[s[curPos]], skipped)
head.suf = newNode
'''return''' head.suf
Node split(Node parent, Node child, '''int''' edgeLength): newNode inserted = Node(parent, child.start, child.start + edgeLenth - 1, parent.depth + edgeLength) parent.children[s[child.start]] = newNodeinserted
child.start += edgeLength
child.length -= edgeLength
newNodeinserted.children[s[child.start]] = child child.parent = newNodeinserted '''return''' newNodeinserted
Node slowScan(Node node, '''int''' start):
curNode = node
curPos = start + node.depth
'''while''' ''true'' '''if''' curNode.children[s[curPos]] !== '''null''' '''break''' :
child = curNode.children[s[curPos]]
edgePos = 0
'''while''' child.start + edgePos <= tex>\leqslant</tex> child.end '''and''' s[child.start + edgePos] == s[curPos] :
curPos++
edgePos++
'''if''' child.start + edgePos > child.end:
curNode = child
'''else''':
curNode = split(curNode, child, edgePos)
'''break'''
* [http://www.academia.edu/3146231/Algorithms_on_strings_trees_and_sequences_computer_science_and_computational_biology ''Gusfield, Dan'' , Algorithms on Strings, Trees and Sequences: Computer Science and Computational Biology // Cambridge University Press, {{---}} 1999. {{---}} ISBN: 0-521-58519-8]
* [http://users-cs.au.dk/cstorm/courses/StrAlg_f12/slides/suffix-tree-construction.pdf ''C. N. Storm'', McCreight's suffix tree construction algorithm]
* [http://pastie.org/9146207 Реализация на языке Java]
== См. также ==
120
правок

Навигация