C# 最快的开始是搜索算法
我需要实现一个搜索算法,它只从字符串开始搜索,而不是从字符串中的任何地方搜索 我对算法还不熟悉,但从我所看到的情况来看,它们似乎通过字符串找到了任何事件 我有一个字符串集合(超过100万个),每次用户键入键盘时都需要搜索这些字符串 编辑: 这将是一个增量搜索。我目前已经用以下代码实现了它,我的搜索范围从300-700毫秒到100多万个可能的字符串。该集合尚未订购,但没有理由不能订购C# 最快的开始是搜索算法,c#,.net,algorithm,search,C#,.net,Algorithm,Search,我需要实现一个搜索算法,它只从字符串开始搜索,而不是从字符串中的任何地方搜索 我对算法还不熟悉,但从我所看到的情况来看,它们似乎通过字符串找到了任何事件 我有一个字符串集合(超过100万个),每次用户键入键盘时都需要搜索这些字符串 编辑: 这将是一个增量搜索。我目前已经用以下代码实现了它,我的搜索范围从300-700毫秒到100多万个可能的字符串。该集合尚未订购,但没有理由不能订购 private ICollection<string> SearchCities(string sea
private ICollection<string> SearchCities(string searchString) {
return _cityDataSource.AsParallel().Where(x => x.ToLower().StartsWith(searchString)).ToArray();
}
private ICollection SearchCities(字符串searchString){
返回_cityDataSource.AsParallel().Where(x=>x.ToLower().StartsWith(searchString)).ToArray();
}
我建议使用linq
string x = "searchterm";
List<string> y = new List<string>();
List<string> Matches = y.Where(xo => xo.StartsWith(x)).ToList();
string x=“searchterm”;
列表y=新列表();
List Matches=y.Where(xo=>xo.StartsWith(x)).ToList();
其中x是按键搜索文本项,y是要搜索的字符串集合,Matches是集合中的匹配项
我用前100万个素数对此进行了测试,下面是从上面改编的代码:
Stopwatch SW = new Stopwatch();
SW.Start();
string x = "2";
List<string> y = System.IO.File.ReadAllText("primes1.txt").Split(' ').ToList();
y.RemoveAll(xo => xo == " " || xo == "" || xo == "\r\r\n");
List <string> Matches = y.Where(xo => xo.StartsWith(x)).ToList();
SW.Stop();
Console.WriteLine("matches: " + Matches.Count);
Console.WriteLine("time taken: " + SW.Elapsed.TotalSeconds);
Console.Read();
Stopwatch SW=新秒表();
SW.Start();
字符串x=“2”;
List y=System.IO.File.ReadAllText(“primes1.txt”).Split(“”).ToList();
y、 RemoveAll(xo=>xo==“”| | xo==“”| | xo==“\r\n”);
List Matches=y.Where(xo=>xo.StartsWith(x)).ToList();
SW.Stop();
Console.WriteLine(“matches:+matches.Count”);
Console.WriteLine(“所用时间:“+SW.已用时间.TotalSeconds”);
Console.Read();
结果是:
比赛:77025
所用时间:0.4240604
当然,这是针对数字进行的测试,我不知道linq之前是否转换了值,或者数字是否有任何区别。一些想法:
首先,需要对一百万个字符串进行排序,这样您就可以“搜索”到第一个匹配的字符串并返回字符串,直到您不再有匹配的字符串为止(可能通过C#List.BinarySearch进行搜索)。这就是你接触尽可能少的字符串的方式
第二,在输入暂停至少500毫秒(给予或接受)之前,您可能不应该尝试点击字符串列表
第三,您对浩瀚空间的查询应该是异步的和可取消的,因为肯定会出现这样的情况:一次努力会被下一次击键所取代
最后,任何后续查询都应首先检查新搜索字符串是否是最新搜索字符串的附加…以便您可以从上一次搜索开始后续搜索(节省大量时间)。我已经改编了实现Trie
的代码
下面的程序演示如何使用Trie
进行快速前缀搜索
为了运行此程序,您需要一个名为“words.txt”的文本文件,其中包含大量单词
编译程序后,将“words.txt”文件复制到与可执行文件相同的文件夹中
运行程序时,键入前缀(如前缀
;)并按返回
),它将列出以该前缀开头的所有单词
这应该是一个非常快速的查找-有关更多详细信息,请参阅Visual Studio杂志文章
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;
}
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.IO;
使用System.Linq;
使用系统文本;
名称空间控制台EAPP1
{
班级计划
{
静态void Main()
{
var trie=新的trie();
InsertRange(File.ReadLines(“words.txt”);
WriteLine(“键入前缀并按回车键”);
while(true)
{
字符串前缀=Console.ReadLine();
if(string.IsNullOrEmpty(前缀))
继续;
var node=trie.Prefix(前缀);
if(node.Depth==prefix.Length)
{
foreach(后缀中的var后缀(节点))
Console.WriteLine(前缀+后缀);
}
其他的
{
Console.WriteLine(“未找到前缀”);
}
Console.WriteLine();
}
}
静态IEnumerable后缀(节点父节点)
{
var sb=新的StringBuilder();
返回后缀(父级,sb)。选择(后缀=>suffix.TrimEnd(“$”);
}
静态IEnumerable后缀(节点父节点,StringBuilder当前)
{
if(parent.IsLeaf())
{
产生返回电流。ToString();
}
其他的
{
foreach(parent.Children中的变量child)
{
当前.Append(子.Value);
foreach(后缀中的var值(子级,当前))
收益回报值;
--电流长度;
}
}
}
}
公共类节点
{
公共字符值{get;set;}
公共列表子项{get;set;}
公共节点父节点{get;set;}
公共整数深度{get;set;}
公共节点(字符值、整数深度、节点父节点)
{
价值=价值;
Children=新列表();
深度=深度;
父母=父母;
}
公共布尔岛()
{
返回子项。计数==0;
}
公共节点FindChildNode(字符c)
{
返回Children.FirstOrDefault(child=>child.Value==c);
}
公共void DeleteChildNode(字符c)
{
for(var i=0;i