迭代存储在集合中的无序元素对

时间:2011-09-11 17:44:30

标签: c# mathematical-optimization

在C#中,我有一组独特的元素,我想为每个无序对执行一些代码。例如,如果我的容器包含{a,b,c},则无序对是(a,b),(a,c)和(b,c)。问题出现在执行2-opt优化的范围内,因此效率是个问题。

  • 我目前的解决方案如下:

    foreach(var a in container) 
    {
        foreach(var b in container)
        {
            if (a < b)
            {
                 // execute code    
            }
        }
     }
    

    显然,如果operator []可用于获取第i个元素(即如果底层数据结构是列表),则可以轻松修改。但对于所有其他容器,解决方案取决于是否存在一些比较功能并不是很有效。

  • 我还尝试了一种基于LINQ语句的公式,它只生成一对所需的对。然而,正如预期的那样,这比第一种方法慢得多。这也适用于使用ElementAt的解决方案。

编辑:这是使用的(改进的)LINQ代码:

var x = from a in container
        from b in container
        where a < b 
        select new KeyValuePair<int,int>(a,b);

与其他解决方案相比,执行速度慢了3-5倍。

  • 这是我在C ++中实现它的方式(获得良好的效率):

    for(auto it1 = container.begin(); it1!=container.end(); ++it1) 
    {
        auto it2 = it1;
        for(++it2; it2!=container.end(); ++it2) 
        {
            // execute code    
        }
     }
    

    不幸的是,要将其转换为C#,需要克隆(内部使用的)枚举器,语言本身不支持。

有没有人有更好的主意/解决方案?

4 个答案:

答案 0 :(得分:1)

您是否尝试先将元素复制到列表中,然后使用索引器([i])运算符执行算法?由于该算法具有二次运行时间,因此在其前面进行线性复制操作可能是微不足道的。你必须自己找出小型,中型和大型容器的实际运行时间......

我认为值得一试,这可能比每次使用比较运算符快得多。

您还可以检查容器是否为IList<T>类型并跳过复制操作。

答案 1 :(得分:1)

如果您不关心订单,可以这样做:

int i = 0;
foreach (var a in list)
{
    int j = 0;
    foreach (var b in list)
    {
        if (i <= j)
            break;

        // execute code    

        j++;
    }

    i++;
}

如果您关心订单,则可以将自己限制为实施IList<T>的集合,其中包含[]运算符。或者您可以先将集合复制到List<T>,然后再使用它。

答案 2 :(得分:0)

C#中的枚举器与您问题中的C ++枚举器不同。在C#中,您既没有容器的begin也没有end元素。您只有Current元素和Next()方法。它允许你产生更多的序列,例如 - 你可以通过无穷大的随机数序列进行枚举,这显然没有开始或结束。

所以 - 你不能只在C ++代码中使用IEnumerable类在C#中执行此操作。最好的方法是使用System.Collection.Generics.IList<T>接口。许多类型(例如数组)都继承了这个接口。

如果你使用IEnumerable,那么在你的类型中你(在大多数情况下)迭代一些集合。如果你这样做 - 你可以实现IList<T>接口。

还有另一种解决方案 - 在C#列表中,引用类型数组仅包含对象的引用。所以 - 您可以将数据复制到本地列表并使用它。但这取决于你的记忆力和性能要求。

答案 3 :(得分:0)

将您的项目放入List或IList中,然后您可以使用与C ++代码非常相似的索引访问它们。

for (int i = 0; i < container.Count(); i++)
for (int j = i+1; j < container.Count(); j++)
{
    var item1 = container.Item[i];
    var item2 = container.Item[j];
}

我希望使用索引而不是n ^ 2比较迭代有序集合会更有效。比较运算符的效率很重要,但您根本不需要进行比较。