C#时间复杂度Array [T] .Contains(T item)vs HashSet <t> .Contains(T item)

时间:2016-05-12 09:32:54

标签: c# arrays time-complexity big-o contains

HashSet(T).Contains(T)(继承自ICollection<T>.Contains(T))的时间复杂度为O(1) 所以,我想知道包含整数的类成员数组的复杂性是什么,因为我努力实现O(1)并且不需要HashSet(T).Add(T) {{1}}。< / p>

由于.NET引用源中显示existence checks 而不是,因此我无法找到找到built-in types的数组实现。

非常感谢任何(进一步)阅读材料或参考资料。

3 个答案:

答案 0 :(得分:7)

您可以看到Array的源代码与任何反射器(也可能在线,没有检查)。 IList.Contains只是:

Array.IndexOf(this,value) >= this.GetLowerBound(0);

Array.IndexOf调用Array.IndexOf<T>,经过一系列一致性检查后,重定向到

EqualityComparer<T>.Default.IndexOf(array, value, startIndex, count)

那个人终于做到了:

int num = startIndex + count;
for (int index = startIndex; index < num; ++index)
{
  if (this.Equals(array[index], value))
      return index;
}
return -1;

因此,只需循环遍历平均复杂度为O(N)的数组。当然,从一开始就很明显,但只是为了提供更多的证据。

答案 1 :(得分:4)

数组源代码在reference source中可用,可以使用ILSpy进行反编译。

在参考源中,您可以在第2753行找到2809:

// -----------------------------------------------------------
// ------- Implement ICollection<T> interface methods --------
// -----------------------------------------------------------

...

[SecuritySafeCritical]
bool Contains<T>(T value) {
    //! Warning: "this" is an array, not an SZArrayHelper. See comments above
    //! or you may introduce a security hole!
    T[] _this = JitHelpers.UnsafeCast<T[]>(this);
    return Array.IndexOf(_this, value) != -1;
}

IndexOf最终会以IndexOf结束,这是一种O(n)算法。

internal virtual int IndexOf(T[] array, T value, int startIndex, int count)
{
    int endIndex = startIndex + count;
    for (int i = startIndex; i < endIndex; i++) {
        if (Equals(array[i], value)) return i;
    }
    return -1;
}

这些方法位于同一源文件中的特殊类SZArrayHelper上,如第2721行所述,这是您正在寻找的实现。

// This class is needed to allow an SZ array of type T[] to expose IList<T>,
// IList<T.BaseType>, etc., etc. all the way up to IList<Object>. When the following call is
// made:
//
//   ((IList<T>) (new U[n])).SomeIListMethod()
//
// the interface stub dispatcher treats this as a special case, loads up SZArrayHelper,
// finds the corresponding generic method (matched simply by method name), instantiates
// it for type <T> and executes it.

关于实现O(1)复杂性,您应该将其转换为HashSet:

var lookupHashSet = new HashSet<T>(yourArray);
...
var hasValue = lookupHashSet.Contains(testValue);

当然,这种转换是O(n)操作。如果你没有很多查询要做,那就没有用了。

请注意此构造函数上的from documentation

  

如果集合包含重复项,则集合将包含每个唯一元素之一。不会抛出异常。因此,结果集的大小与集合的大小不同。

答案 2 :(得分:0)

您实际上可以看到List<T>的来源,但您需要在线查找。这是one source

任何纯列表/数组bool Contains(T item)检查都是O(N)复杂度,因为需要检查每个元素。 .NET也不例外。 (如果您设计的数据结构表现为列表,但也包含布隆过滤器辅助数据结构,那将是另一个故事。)