C# 二进制搜索速度较慢,我做错了什么?

C# 二进制搜索速度较慢,我做错了什么?,c#,performance,list,intersection,C#,Performance,List,Intersection,编辑:看来这是正常的行为,那么有人能推荐一种更快的方法来处理这些交叉点吗 所以我的问题是这个。我有8000个列表(每个列表中都有字符串)。对于每个列表(大小从50到400),我将其与其他列表进行比较,并根据交叉点编号执行计算。我会的 列表1(相交)列表1=编号 列表1(相交)列表2=编号 列表1(相交)列表888=编号 我对每个列表都这样做。以前,我有HashList,我的代码基本上是这样的:(嗯,我实际上是在搜索一个对象的属性,所以我 必须对代码进行一些修改,但基本上是这样的: 我有我的两个版

编辑:看来这是正常的行为,那么有人能推荐一种更快的方法来处理这些交叉点吗

所以我的问题是这个。我有8000个列表(每个列表中都有字符串)。对于每个列表(大小从50到400),我将其与其他列表进行比较,并根据交叉点编号执行计算。我会的

列表1(相交)列表1=编号

列表1(相交)列表2=编号

列表1(相交)列表888=编号

我对每个列表都这样做。以前,我有HashList,我的代码基本上是这样的:(嗯,我实际上是在搜索一个对象的属性,所以我 必须对代码进行一些修改,但基本上是这样的:

我有我的两个版本,但如果有人知道任何更快的,请让我知道

循环浏览所有列表,获取每个列表,从list1开始,然后执行以下操作:

foreach (List list in AllLists)
{
    if (list1_length < list_length) //just a check to so I'm looping through the                  
                                    //smaller list
    {
        foreach (string word in list1)
        {
            if (block.generator_list.Contains(word))
            {
                //simple integer count
            }
        }
    }
// a little more code, but the same, but looping through the other list if it's smaller/bigger
foreach(所有列表中的列表)
{
if(list1_length
然后,我将列表制作成常规列表,并应用Sort(),这将我的代码更改为

foreach (List list in AllLists)
{
    if (list1_length < list_length) //just a check to so I'm looping through the                  
                                    //smaller list
    {
        for (int i = 0; i < list1_length; i++)
        {
            var test = list.BinarySearch(list1[i]);
            if (test > -1)
            {
                //simple integer count
            }
        }
    }
foreach(所有列表中的列表)
{
if(list1_length-1)
{
//简单整数计数
}
}
}
第一个版本大约需要6秒,另一个版本需要20多秒(我只是停在那里,因为否则它将需要超过一分钟!!!)(这是一个很小的数据子集)


我确信某个地方有一个严重的错误,但我找不到它。

我发现迭代/搜索任何类型的集合时,最重要的考虑因素之一是非常仔细地选择集合类型。为了您的目的,迭代普通集合并不是最理想的。请尝试使用以下方法:

System.Collections.Generic.HashSet<T>
System.Collections.Generic.HashSet

使用Contains()方法在两个较短的列表上进行迭代(正如您已经提到的那样),应该可以提供接近O(1)的性能,与泛型字典类型中的键查找相同。

我已经尝试了三种不同的方法来实现这一点(假设我正确理解了问题)。请注意,我使用了
HashSet
,以便更轻松地生成随机输入。 设置:

List<HashSet<int>> allSets = new List<HashSet<int>>();
Random rand = new Random();
for(int i = 0; i < 8000; ++i) {
    HashSet<int> ints = new HashSet<int>();
    for(int j = 0; j < rand.Next(50, 400); ++j) {
        ints.Add(rand.Next(0, 1000));
    }
    allSets.Add(ints);
}
第一种方法: 使用
IEnumerable.Intersect()
获取与其他列表的交集,并选中
IEnumerable.Count()
获取交集的大小

var intersect = allSets[i].Intersect(allSets[j]);
count = intersect.Count();
这是最慢的一次,平均177次

第二种方法: 克隆了我正在相交的两个集合中的较小集合,然后使用ISet.IntersectWith()
并检查结果集合的计数

HashSet<int> intersect;
HashSet<int> intersectWith;
        if(allSets[i].Count < allSets[j].Count) {
            intersect = new HashSet<int>(allSets[i]);
            intersectWith = allSets[j];
        } else {
            intersect = new HashSet<int>(allSets[j]);
            intersectWith = allSets[i];
        }
        intersect.IntersectWith(intersectWith);
        count = intersect.Count;
    }
}
这种方法是迄今为止最快的(如预期的那样),平均为66秒

结论
您使用的方法是这三种方法中最快的。我当然想不出一种更快的单线程方法来实现这一点。也许有更好的并发解决方案。

在代码中,您在哪里对列表进行排序?或者您是在这之前进行排序的。HashList是O(1)分期付款的,BinarySearch()是O(logN)。所以这是完全正常的。嗨,是的,我在这之前做过。真的,所以没有其他方法可以让它更快?哈希列表是一种方法。考虑到你正在做大约8000 x 4000个列表比较(如果我理解正确的话),所以这需要一段时间!如果你有一个固定的字符串列表,那么迭代所有这些字符串可能会更快,但是考虑到这一点,我认为你上面的方法实际上会更快。不幸的是,我想不出其他方法来加速它。我会尝试一下,因为我的结果只针对一小部分,而且需要花费时间我喜欢用8分钟把它们全部搞定。可能是因为我不是相交集,而是碰巧是哈希集的对象的属性(我的集是字符串,但我认为这并不重要)?如果我做并行处理,我可以把每个交叉点的交叉点编号放在哪里?似乎如果我做一个矩阵,我会访问同一个矩阵,这会减慢速度。如果我做一个具有3个属性的对象,set1、set2和intersection_number,那么最终我将只有64000个该对象的实例?是交叉对象吗属性慢于仅获取这些属性并将其设置为一组(如您的所有集)和它们相交?等等,我不是已经在使用哈希集了吗,或者你的意思不同了吗?你在使用列表类型是的,我在使用列表…?你能澄清或展示一个例子吗?好的,你已经在使用哈希集了,这在你的代码示例中没有显示,在你的解释中我也不清楚。如果你已经这样做了,那么你需要考虑比较8000个列表本身就是瓶颈。使用简单的循环,你将无法达到最佳性能。考虑Sturth.thordy.task.Stand类型并行化你的计算。如果我有时间的话,我会发布一个例子。谢谢,我真的研究过了,而且我在没有真正理解我的情况下实现了它。这样做,我只获得了3倍的速度提升,但我不确定如何处理这样一个事实,即我在同一时间访问相同的变量,并且我希望将交叉点编号存储在某个位置。目前,我认为我的效率低下导致了中途出现内存不足异常(可能也是因为我的哈希集由
HashSet<int> intersect;
HashSet<int> intersectWith;
        if(allSets[i].Count < allSets[j].Count) {
            intersect = new HashSet<int>(allSets[i]);
            intersectWith = allSets[j];
        } else {
            intersect = new HashSet<int>(allSets[j]);
            intersectWith = allSets[i];
        }
        intersect.IntersectWith(intersectWith);
        count = intersect.Count;
    }
}
for(int i = 0; i < allSets.Count; ++i) {
    for(int j = i + 1; j < allSets.Count; ++j) {
        count = 0;
        if(allSets[i].Count < allSets[j].Count) {
            loopingSet = allSets[i];
            containsSet = allSets[j];
        } else {
            loopingSet = allSets[j];
            containsSet = allSets[i];
        }
        foreach(int k in loopingSet) {
            if(containsSet.Contains(k)) {
                ++count;
            }
        }
    }
}