我修改了代码this article from Visual Studio Magazine,它实现了Trie
。
下面的程序演示如何使用Trie
做快速前缀搜索。
为了运行这个程序,你需要所谓的“words.txt”文字的大名单的文本文件。You can download one from Github here。
编译完程序后,将“words.txt”文件复制到与可执行文件相同的文件夹中。
当您运行程序时,键入一个前缀(如prefix
;))并按return
,它会列出以该前缀开头的所有单词。
这应该是一个非常快速的查找 - 请参阅Visual Studio Magazine文章以获取更多详细信息!
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace ConsoleApp1
{
class Program
{
static void Main()
{
var trie = new Trie();
trie.InsertRange(File.ReadLines("words.txt"));
Console.WriteLine("Type a prefix and press return.");
while (true)
{
string prefix = Console.ReadLine();
if (string.IsNullOrEmpty(prefix))
continue;
var node = trie.Prefix(prefix);
if (node.Depth == prefix.Length)
{
foreach (var suffix in suffixes(node))
Console.WriteLine(prefix + suffix);
}
else
{
Console.WriteLine("Prefix not found.");
}
Console.WriteLine();
}
}
static IEnumerable<string> suffixes(Node parent)
{
var sb = new StringBuilder();
return suffixes(parent, sb).Select(suffix => suffix.TrimEnd('$'));
}
static IEnumerable<string> suffixes(Node parent, StringBuilder current)
{
if (parent.IsLeaf())
{
yield return current.ToString();
}
else
{
foreach (var child in parent.Children)
{
current.Append(child.Value);
foreach (var value in suffixes(child, current))
yield return value;
--current.Length;
}
}
}
}
public class Node
{
public char Value { get; set; }
public List<Node> Children { get; set; }
public Node Parent { get; set; }
public int Depth { get; set; }
public Node(char value, int depth, Node parent)
{
Value = value;
Children = new List<Node>();
Depth = depth;
Parent = parent;
}
public bool IsLeaf()
{
return Children.Count == 0;
}
public Node FindChildNode(char c)
{
return Children.FirstOrDefault(child => child.Value == c);
}
public void DeleteChildNode(char c)
{
for (var i = 0; i < Children.Count; i++)
if (Children[i].Value == c)
Children.RemoveAt(i);
}
}
public class Trie
{
readonly Node _root;
public Trie()
{
_root = new Node('^', 0, null);
}
public Node Prefix(string s)
{
var currentNode = _root;
var result = currentNode;
foreach (var c in s)
{
currentNode = currentNode.FindChildNode(c);
if (currentNode == null)
break;
result = currentNode;
}
return result;
}
public bool Search(string s)
{
var prefix = Prefix(s);
return prefix.Depth == s.Length && prefix.FindChildNode('$') != null;
}
public void InsertRange(IEnumerable<string> items)
{
foreach (string item in items)
Insert(item);
}
public void Insert(string s)
{
var commonPrefix = Prefix(s);
var current = commonPrefix;
for (var i = current.Depth; i < s.Length; i++)
{
var newNode = new Node(s[i], current.Depth + 1, current);
current.Children.Add(newNode);
current = newNode;
}
current.Children.Add(new Node('$', current.Depth + 1, current));
}
public void Delete(string s)
{
if (!Search(s))
return;
var node = Prefix(s).FindChildNode('$');
while (node.IsLeaf())
{
var parent = node.Parent;
parent.DeleteChildNode(node.Value);
node = parent;
}
}
}
}
所以你想找到一个集合中的所有字符串,使得你的输入字符串是它们的前缀?你应该看看[String.startsWith](https://msdn.microsoft.com/en-us/library/bb383988.aspx)。你也应该自己尝试一下,我们会指出错误,并从那里引导你。 – hnefatl
你将不得不更具体一些......你可以发布一些代码来显示你到目前为止的内容吗?并更准确地说明你的意思。 –
如果我怀疑您正在进行增量搜索,那么您可能需要查看“Trie”数据结构。这可以非常快速地发现集合中以指定前缀开头的所有字符串。有关详细信息,请参见[此Visual Studio杂志文章](https://visualstudiomagazine.com/articles/2015/10/20/text-pattern-search-trie-class-net.aspx)。 –