Как оптимизировать алгоритма префиксного дерева?
Мне прилетает большое кол-во строк, которые выглядят вот так:
"reply/command/name",
"reply/command/namef",
"reply1/command1/name1"
Мне необходимо их разделять по / и группировать. Хочется видеть такой результат:
reply
command
name
namef
reply1
command1
name1
Я написал такой алгоритм, который достаточно делает нужное, но не так быстро и оптимально, как хотелось бы. Вот решение:
public class Trie
{
public Trie(
string part,
int level,
Trie? root = null,
Trie? parent = null )
{
Part = part;
Level = level;
Parent = parent;
Root = root;
}
public string Part { get; }
public int Level { get; }
public Trie? Parent { get; }
private Trie? Root { get; }
private readonly Dictionary<string, Trie> _children = new();
public bool Add(string[] topic, int level)
{
var changedTopicCount = false;
if ( topic.Length <= 0 )
return false;
if (!_children.ContainsKey(topic[0]))
{
var node = new Trie(topic[0], level, Root, this);
_children.TryAdd(topic[ 0 ], node);
changedTopicCount = true;
}
if(!_children[topic[0]]
.Add(topic.Skip(1).ToArray(),
level + 1)
&& !changedTopicCount)
return changedTopicCount;
changedTopicCount = true;
return changedTopicCount;
}
}
использовать вот так:
public class UseTree
{
public UseTree()
{
var root = new Trie( "host", 0 );
TreeRoot = root;
}
private Trie TreeRoot { get; }
public void Add()
{
var array = new[]
{
"reply/command/name",
"reply/command/namef",
"reply1/command1/name1"
};
foreach (var element in array)
{
TreeRoot.Add(
element.Split('/'),
1);
}
}
}
Подскажите, пожалуйста, что тут можно улучшить?
Стоит ли искать пакеты с производительной реализацией Dictionary?
Ответы (1 шт):
Автор решения: tym32167
→ Ссылка
Чет как то сложно, да и пересоздавать массив topic.Skip(1).ToArray() чутка расточительно.
Ну вот я бы как написал
public class TrieNode
{
private Dictionary<string, TrieNode> _children = new Dictionary<string, TrieNode>();
public void Add(string[] data, int index = 0)
{
if (index >= data.Length) return;
var word = data[index];
if (!_children.ContainsKey(word)) _children.Add(word, new TrieNode());
_children[word].Add(data, index + 1);
}
public void Print(string prefix)
{
foreach (var kv in _children)
{
Console.WriteLine($"{prefix}{kv.Key}");
kv.Value.Print(prefix + prefix);
}
}
}
Проверка
var data = new[]
{
"reply/command/name",
"reply/command/namef",
"reply1/command1/name1"
};
var root = new TrieNode();
foreach (var dataItem in data)
{
root.Add(dataItem.Split('/'));
}
root.Print("\t");
Вывод
reply
command
name
namef
reply1
command1
name1
В этом алгоритме скорость уже линейная, быстрее этого только дополниетльные извращения со строками.