5

我正在尝试提高以下(示例)代码的性能。

Object[] inputKeys = new Object[10];
inputKeys[0] = "4021";
inputKeys[1] = "3011";
inputKeys[2] = "1010";
inputKeys[3] = "1020";
inputKeys[4] = "1030";

然后比较输入键。

for (int i = 0; i < 5; i++)
{
    for (int j = 0; j < 5; j++)
    {
        bool result = inputKeys[i].Equals(inputKeys[j]);
    }
}

inputKeys 可以是所有类型stringint32DateTime

.Equals当它达到数百万次时,性能会出现巨大的下降。

关于如何提高这条线的性能(平等检查)的任何建议?

我试过这个:使用下面类的数组而不是 Object 数组来保存键。在那里我保留了键类型和键值。

public class CustomKey : IEquatable<CustomKey>{
    internal int KeyType { get; private set; }

    internal string ValueString { get; private set; }
    internal int ValueInteger { get; private set; }
    internal DateTime ValueDateTime { get; private set; }

    internal CustomKey(string keyValue)
    {
        this.KeyType = 0;
        this.ValueString = (string)keyValue;
    }

    internal CustomKey(int keyValue)
    {
        this.KeyType = 1;
        this.ValueInteger = (int)keyValue;
    }

    internal CustomKey(DateTime keyValue)
    {
        this.KeyType = 2;
        this.ValueDateTime = (DateTime)keyValue;
    }

    public bool Equals(CustomKey other)
    {
        if (this.KeyType != other.KeyType)
        {
            return false;
        }
        else
        {
            if (this.KeyType == 0)
            {
                return this.ValueString.Equals(other.ValueString);
            }
            else if (this.KeyType == 1)
            {
                return this.ValueInteger.Equals(other.ValueInteger);
            }
            else if (this.KeyType == 2)
            {
                return this.ValueDateTime.Equals(other.ValueDateTime);
            }
            else
            {
                return false;
            }
        }
    }
}

但表现更差。

4

5 回答 5

2

您的比较循环效率低下。我建议你尝试使用:

Distinct<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)

IEqualityComparer为该类型定义您的并将其传递给该方法。你不会得到一个布尔值,但你会得到一个IEnumerable包含没有重复的列表。

于 2012-12-18T17:55:02.410 回答
2

作为算法效率的一个例子,你的第一个代码可以重写

for (int i = 0; i < 5; i++)
{
    for (int j = i; j < 5; j++)
    {
        bool result = inputKeys[i].Equals(inputKeys[j]);
    }
}

因为 x.Equals(y) 将给出与 y.Equals 相同的结果,所以您不需要同时检查两种方式。 http://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx

Equals 的新实现应该遵循

x.Equals(y) 返回与 y.Equals(x) 相同的值。

于 2012-12-18T18:07:08.483 回答
1

正如评论中所说,您算法的主要负担是您必须将所有内容与所有内容进行比较,这会影响您的表现。对于 100K 元素,这意味着 100k^2 ......或大约 10K 百万组合......你可以看到你有问题的地方。最好的选择是修改算法,但是,如果您仍然确定或没有任何其他选择,请考虑:

首先划分你的对象,稍后比较:

示例:如果您有 100K 个对象均匀分布,您将拥有 33K 个整数、33K 个字符串和 33K 个日期时间,然后您可以将它们相互比较并忽略它们之间的组合。

100K^2 = 10K 百万

(30K^2) * 3 = 27 亿组合 + 100K 对其列表中的每个元素进行排序

扩展您的群组

如果您不太关心内存,您可以对结果进行哈希处理以进一步细化您的组。基本上构建一个网格......这取决于您的问题非常具体

这背后的想法是隔离不能真正相等的事物,这是对先前想法的扩展,但是组越多,组越小,您的表现就越快

这样你就可以有10个组

  • 少于 5 个字符的字符串
  • 5 到 50 个字符之间的字符串
  • 长度超过 50 个字符的字符串

等等...

如果您重做数学运算(再次,对于均匀分布的样本)

总迭代次数 = 10K^2 * 10 + 100K ~ 1 亿次迭代(10 组 + 组成这些组的价格)

实际复杂度 = (n/m)^2 * m + n(其中 n = 元素数,m = 假设均匀分布的组数。

于 2012-12-18T18:15:34.733 回答
0

尝试获取每个对象的哈希码并将它们与object.GetHashCode(). 不确定调用GetHashCode()几百万次的开销,但比较两个整数可能会比Equals(object)方法快得多。

于 2012-12-18T17:55:29.123 回答
0

使用哈希表(或更好的字典)来存储您的项目。您的方法具有 (N^2) 的顺序,通过使用哈希表,您可以将运行时间复杂度降低到 O(N),其中 N 是数字。

为此,请使用哈希键创建一个哈希表,如果发生冲突,请将项目添加到链表中。当只需要检查同一桶中的对象是否相等时,不应该太多。

我希望这是清楚和有帮助的。

于 2012-12-18T18:12:42.980 回答