#c# #data-structures #suffix-tree
Вопрос:
Я реализовал базовый поиск для исследовательского проекта. Я пытаюсь сделать поиск более эффективным, построив дерево суффиксов. Меня интересует реализация алгоритма Укконена на языке C#. Я не хочу тратить время на то, чтобы прокручивать свой собственный, если такая реализация существует.
Комментарии:
1. Можете ли вы вообще подробнее ответить на свой вопрос?
2. Я пытаюсь реализовать поиск в рамках исследовательского проекта. Я реализовал обратный индекс и инкрементное заполнение индекса. Затем я хотел сделать поиск еще более эффективным, но не хотел сворачивать свою собственную реализацию ST, если она существует.
Ответ №1:
Трудный вопрос. Вот самое близкое совпадение, которое я смог найти: http://www.codeproject.com/KB/recipes/ahocorasick.aspx, который является реализацией алгоритма сопоставления строк Ахо-Корасика. Теперь алгоритм использует суффиксальную древовидную структуру для: http://en.wikipedia.org/wiki/Aho-Corasick_algorithm
Теперь, если вам нужно дерево префиксов, в этой статье утверждается, что у вас есть реализация для вас: http://www.codeproject.com/KB/recipes/prefixtree.aspx
<ЮМОР> Теперь, когда я сделал твою домашнюю работу, как насчет того, чтобы ты подстриг мой газон? (Ссылка: http://flyingmoose.org/tolksarc/homework.htm) </ЮМОР>
Редактировать: Я нашел реализацию дерева суффиксов C#, которая была портом C , опубликованного в блоге: http://code.google.com/p/csharsuffixtree/source/browse/#svn/trunk/suffixtree
Изменить: В Codeplex появился новый проект, посвященный деревьям суффиксов: http://suffixtree.codeplex.com/
Комментарии:
1. Я ищу дерево суффиксов.
Ответ №2:
Вуз, только что закончил реализацию библиотеки .NET (c#), содержащей различные реализации trie. Среди них:
- Классическая трие
- Патрисия три
- Суффикс трие
- Попытка с использованием алгоритма Укконена
Я старался сделать исходный код легко читаемым. Использование также очень прямолинейно:
using Gma.DataStructures.StringSearch;
...
var trie = new UkkonenTrie<int>(3);
//var trie = new SuffixTrie<int>(3);
trie.Add("hello", 1);
trie.Add("world", 2);
trie.Add("hell", 3);
var result = trie.Retrieve("hel");
Библиотека хорошо протестирована и также опубликована в виде пакета TrieNet NuGet.
Комментарии:
1. Спасибо вам за реализацию алгоритма Укконена. Отличная работа.
Ответ №3:
Вот реализация дерева суффиксов, которая достаточно эффективна. Я не изучал реализацию Укконена, но время работы этого алгоритма, на мой взгляд, вполне разумно, примерно O(N Log N)
. Обратите внимание, что количество внутренних узлов в созданном дереве равно количеству букв в родительской строке.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using NUnit.Framework;
namespace FunStuff
{
public class SuffixTree
{
public class Node
{
public int Index = -1;
public Dictionary<char, Node> Children = new Dictionary<char, Node>();
}
public Node Root = new Node();
public String Text;
public void InsertSuffix(string s, int from)
{
var cur = Root;
for (int i = from; i < s.Length; i)
{
var c = s[i];
if (!cur.Children.ContainsKey(c))
{
var n = new Node() {Index = from};
cur.Children.Add(c, n);
// Very slow assertion.
Debug.Assert(Find(s.Substring(from)).Any());
return;
}
cur = cur.Children[c];
}
Debug.Assert(false, "It should never be possible to arrive at this case");
throw new Exception("Suffix tree corruption");
}
private static IEnumerable<Node> VisitTree(Node n)
{
foreach (var n1 in n.Children.Values)
foreach (var n2 in VisitTree(n1))
yield return n2;
yield return n;
}
public IEnumerable<int> Find(string s)
{
var n = FindNode(s);
if (n == null) yield break;
foreach (var n2 in VisitTree(n))
yield return n2.Index;
}
private Node FindNode(string s)
{
var cur = Root;
for (int i = 0; i < s.Length; i)
{
var c = s[i];
if (!cur.Children.ContainsKey(c))
{
// We are at a leaf-node.
// What we do here is check to see if the rest of the string is at this location.
for (var j=i; j < s.Length; j)
if (cur.Index j >= Text.Length || Text[cur.Index j] != s[j])
return null;
return cur;
}
cur = cur.Children[c];
}
return cur;
}
public SuffixTree(string s)
{
Text = s;
for (var i = s.Length - 1; i >= 0; --i)
InsertSuffix(s, i);
Debug.Assert(VisitTree(Root).Count() - 1 == s.Length);
}
}
[TestFixture]
public class TestSuffixTree
{
[Test]
public void TestBasics()
{
var s = "banana";
var t = new SuffixTree(s);
var results = t.Find("an").ToArray();
Assert.AreEqual(2, results.Length);
Assert.AreEqual(1, results[0]);
Assert.AreEqual(3, results[1]);
}
}
}
Комментарии:
1. -@cdiggins, извините за мое невежество. Это мой первый раз, когда я вижу класс в другом классе. В вашем коде,
public class Node
находится внутриpublic class SuffixTree
, какой здесь навык?2. Я знаю, что этот пост старый, но, похоже, с этим кодом возникла проблема при некоторых обстоятельствах, которые я, похоже, не могу понять. Установите S = «TAGGAAATTC» и попробуйте t.Find(«CTATT»), и строка f (Текст[cur.Индекс j] != s[j]) приведет к исключению IndexOutsideBoundsOfArray. Ваша реализация кажется очень элегантной и достаточно эффективной (ввести Ukkoken немного … сложно). Кажется, я не могу найти способ обойти эту ошибку.
3. @Ilhan Я только что внес изменения, которые должны исправить ошибку.
4. Поиск не работает должным образом в этой реализации для случаев, когда есть 2 совпадения.