C# 快速关系搜索
存在多对多关系列表(N=1000000)。我需要尽可能快地确定列表中的关系索引,并枚举特定项的所有关系 我知道可以为from/to创建查找表(时间为O(1)),但它的大小太大(N*N)。我知道我可以使用二进制搜索(时间为O(log(N)),但它仍然非常慢。还有其他解决办法吗 C#代码:C# 快速关系搜索,c#,search,relation,C#,Search,Relation,存在多对多关系列表(N=1000000)。我需要尽可能快地确定列表中的关系索引,并枚举特定项的所有关系 我知道可以为from/to创建查找表(时间为O(1)),但它的大小太大(N*N)。我知道我可以使用二进制搜索(时间为O(log(N)),但它仍然非常慢。还有其他解决办法吗 C#代码: 公共类关系 { 公共int来自; 公共int至; } 公共类表 { 公共列表关系{get;}=new List(); 公共无效添加(int-from,int-to) { if(IndexOf(from,to)=-
公共类关系
{
公共int来自;
公共int至;
}
公共类表
{
公共列表关系{get;}=new List();
公共无效添加(int-from,int-to)
{
if(IndexOf(from,to)=-1)
{
Add(新关系(){From=From,To=To});
}
}
public int IndexOf(int-from,int-to)
{
//这个算法进行O(N)比较,但我需要O(1)
for(int i=0;i
以下是包含两个词典的版本:
public class Table
{
public Dictionary<int, HashSet<int>> froms { get; } = new Dictionary<int, HashSet<int>>();
public Dictionary<int, HashSet<int>> tos { get; } = new Dictionary<int, HashSet<int>>();
public void Add(int from, int to)
{
if (!Contains(from, to))
{
if (!froms.ContainsKey(from))
{
froms.Add(from, new HashSet<int> { to });
}
else
{
froms[from].Add(to);
}
if (!tos.ContainsKey(to))
{
tos.Add(to, new HashSet<int> { from });
}
else
{
tos[to].Add(from);
}
}
}
public bool Contains(int from, int to)
{
if (!froms.ContainsKey(from))
return false;
if (!froms[from].Contains(to))
return false;
return true;
}
public IEnumerable<int> FromsOf(int to)
{
if(tos.ContainsKey(to))
return tos[to];
else
return new List<int>();
}
}
class Program
{
static void Main(string[] args)
{
Random r = new Random();
Table t = new Table();
int N = 1000000;
for (int i = 0; i < N; i++)
t.Add(r.Next(N), r.Next(N));
DateTime t1 = DateTime.Now;
for (int i = 0; i < N; i++)
{
if (t.Contains(r.Next(N), r.Next(N)))
{
// do something
}
}
DateTime t2 = DateTime.Now;
for (int i = 0; i < N; i++)
{
foreach (int j in t.FromsOf(r.Next(N)))
{
// do something
}
}
DateTime t3 = DateTime.Now;
Console.WriteLine($"IndexOf speed = {(t2 - t1).TotalMilliseconds / N}ms");
Console.WriteLine($"FromsOf speed = {(t3 - t2).TotalMilliseconds / N}ms");
Console.ReadKey();
}
}
公共类表
{
公共字典froms{get;}=new Dictionary();
公共字典tos{get;}=新字典();
公共无效添加(int-from,int-to)
{
如果(!包含(从,到))
{
如果(!froms.ContainsKey(from))
{
Add(from,新HashSet{to});
}
其他的
{
froms[from]。添加(到);
}
如果(!tos.ContainsKey(to))
{
Add(to,newhashset{from});
}
其他的
{
tos[to]。添加(从);
}
}
}
公共布尔包含(int-from,int-to)
{
如果(!froms.ContainsKey(from))
返回false;
如果(!froms[from].包含(到))
返回false;
返回true;
}
公共IEnumerable FromsOf(int-to)
{
如果(tos.ContainsKey(to))
返回到;
其他的
返回新列表();
}
}
班级计划
{
静态void Main(字符串[]参数)
{
随机r=新随机();
表t=新表();
int N=1000000;
对于(int i=0;i
输出:
速度指数=0.0003220099毫秒
FromsOf速度=0.0003799996ms
我在dictionary中尝试使用dictionary,它也非常快,但内存使用量大约为33*N(对于任务管理器132 Mb中的N=10000000内存使用量) 代码:
公共类关系
{
公共int来自;
公共int至;
}
公共类表
{
公共列表关系{get;}=new List();
公共字典FromDic=新字典();
公共无效添加(int-from,int-to)
{
if(IndexOf(from,to)=-1)
{
int index=关系。计数;
Add(新关系(){From=From,To=To});
词典;
如果(!FromDic.TryGetValue(from,out innerDic))
{
innerDic=新字典();
FromDic[from]=内部DIC;
}
innerDic[to]=索引;
}
}
public int IndexOf(int-from,int-to)
{
托迪奇词典;
整数指数;
if(FromDic.TryGetValue(from,out toDic)和&toDic.TryGetValue(to,out index))
收益指数;
返回-1;
}
公共IEnumerable TosOf(int-from)
{
词典;
if(FromDic.TryGetValue(from,out innerDic))返回innerDic.Keys;
返回新列表();
}
}
班级计划
{
静态void Main(字符串[]参数)
{
随机r=新随机();
表t=新表();
int N=100000;
DateTime t0=DateTime.Now;
对于(inti=0;ipublic class Table
{
public Dictionary<int, HashSet<int>> froms { get; } = new Dictionary<int, HashSet<int>>();
public Dictionary<int, HashSet<int>> tos { get; } = new Dictionary<int, HashSet<int>>();
public void Add(int from, int to)
{
if (!Contains(from, to))
{
if (!froms.ContainsKey(from))
{
froms.Add(from, new HashSet<int> { to });
}
else
{
froms[from].Add(to);
}
if (!tos.ContainsKey(to))
{
tos.Add(to, new HashSet<int> { from });
}
else
{
tos[to].Add(from);
}
}
}
public bool Contains(int from, int to)
{
if (!froms.ContainsKey(from))
return false;
if (!froms[from].Contains(to))
return false;
return true;
}
public IEnumerable<int> FromsOf(int to)
{
if(tos.ContainsKey(to))
return tos[to];
else
return new List<int>();
}
}
class Program
{
static void Main(string[] args)
{
Random r = new Random();
Table t = new Table();
int N = 1000000;
for (int i = 0; i < N; i++)
t.Add(r.Next(N), r.Next(N));
DateTime t1 = DateTime.Now;
for (int i = 0; i < N; i++)
{
if (t.Contains(r.Next(N), r.Next(N)))
{
// do something
}
}
DateTime t2 = DateTime.Now;
for (int i = 0; i < N; i++)
{
foreach (int j in t.FromsOf(r.Next(N)))
{
// do something
}
}
DateTime t3 = DateTime.Now;
Console.WriteLine($"IndexOf speed = {(t2 - t1).TotalMilliseconds / N}ms");
Console.WriteLine($"FromsOf speed = {(t3 - t2).TotalMilliseconds / N}ms");
Console.ReadKey();
}
}
public class Relation
{
public int From;
public int To;
}
public class Table
{
public List<Relation> Relations { get; } = new List<Relation>();
public Dictionary<int, Dictionary<int, int>> FromDic = new Dictionary<int, Dictionary<int, int>>();
public void Add(int from, int to)
{
if (IndexOf(from, to) == -1)
{
int index = Relations.Count;
Relations.Add(new Relation() { From = from, To = to });
Dictionary<int, int> innerDic;
if (!FromDic.TryGetValue(from, out innerDic))
{
innerDic = new Dictionary<int, int>();
FromDic[from] = innerDic;
}
innerDic[to] = index;
}
}
public int IndexOf(int from, int to)
{
Dictionary<int, int> toDic;
int index;
if (FromDic.TryGetValue(from, out toDic) && toDic.TryGetValue(to, out index))
return index;
return -1;
}
public IEnumerable<int> TosOf(int from)
{
Dictionary<int, int> innerDic;
if (FromDic.TryGetValue(from, out innerDic)) return innerDic.Keys;
return new List<int>();
}
}
class Program
{
static void Main(string[] args)
{
Random r = new Random();
Table t = new Table();
int N = 100000;
DateTime t0 = DateTime.Now;
for (int i = 0; i < N; i++) t.Add(r.Next(N), r.Next(N));
DateTime t1 = DateTime.Now;
Console.WriteLine($"Add speed = {(t1 - t0).TotalMilliseconds * 1000 / N}mks");
for (int i = 0; i < N; i++)
{
if (t.IndexOf(r.Next(N), r.Next(N)) != -1)
{
// do something
}
}
DateTime t2 = DateTime.Now;
Console.WriteLine($"IndexOf speed = {(t2 - t1).TotalMilliseconds * 1000 / N}mks");
for (int i = 0; i < N; i++)
{
foreach (int j in t.TosOf(r.Next(N)))
{
// do something
}
}
DateTime t3 = DateTime.Now;
Console.WriteLine($"TosOf speed = {(t3 - t2).TotalMilliseconds * 1000 / N}mks");
Console.ReadKey();
}
}