这些Dictionary方法的复杂性是什么?

时间:2011-09-23 17:25:02

标签: c# complexity-theory time-complexity

任何人都可以解释以下Dictionary方法的复杂性吗?

ContainsKey(key)
Add(key,value);

我想弄清楚我写的方法的复杂性:

public void DistinctWords(String s)
{
    Dictionary<string,string> d = new Dictionary<string,string>();
    String[] splitted = s.split(" ");
    foreach ( String ss in splitted)
    { 
        if (!d.containskey(ss))
            d.add(ss,null);
    } 
}

我假设2个字典方法具有log(n)复杂度,其中 n 是字典中的键数。这是对的吗?

6 个答案:

答案 0 :(得分:27)

它写在Dictionary ...

的文档中
  

Dictionary泛型类提供从一组键到一组值的映射。字典的每个添加都包含一个值及其关联的键。通过使用其键来检索值非常快,接近于O(1),因为Dictionary类是作为哈希表实现的。

对于Add函数:

  

如果Count小于容量,则此方法接近O(1)操作。如果必须增加容量以容纳新元素,则此方法将成为O(n)操作,其中n为Count。

答案 1 :(得分:13)

这两种方法都有不变的复杂性:

  • ContainsKey(key) - O(1)
  • 添加(键,值) - O(1)

答案 2 :(得分:11)

这个例程总体上是O(m)时间复杂度,m是搜索中的字符串数。

这是因为Dictionary.ContainsDictionary.Add都是(通常)O(1)操作。

(稍微复杂一点,因为Dictionary.Add对于词典中的n个项目可以是O(n),但只有当词典容量很小时才这样。因此,如果你构造一个具有足够大容量的词典在前面,对于m个字符串条目,它将是O(m)。)

话虽这么说,如果你只使用字典进行存在检查,你可以使用HashSet<string>。这将允许你写:

  public void DistinctWords(String s)
  {
     HashSet<string> hash = new HashSet<string>(s.Split(' '));

     // Use hash here...

由于你的字典是一个局部变量,并且没有存储(至少在你的代码中),你也可以使用LINQ:

 var distinctWords = s.Split(' ').Distinct();

答案 3 :(得分:7)

这是不正确的,通常字典/散列表查找是O(1)。为此,它将从您正在寻找的密钥生成哈希值,并仅将其与具有相同哈希值的项进行比较 - 使用良好的哈希算法,这被认为是总体上的O(1)(amortized O(1) - 只有在极少数情况下,必须增加容量才能增加O(n)。

答案 4 :(得分:2)

两者都是恒定的时间:

http://msdn.microsoft.com/en-us/library/kw5aaea4.aspx

http://msdn.microsoft.com/en-us/library/k7z0zy8k.aspx

但有一点需要注意:

“如果Count小于容量,则此方法接近O(1)操作。如果必须增加容量以容纳新元素,则此方法变为O(n)操作,其中n为Count。”

答案 5 :(得分:2)

ContainsKey和Add方法接近于O(1)。

ContainsKey文档:

  

此方法接近O(1)操作。

添加文档:

  

如果Count小于容量,则此方法接近O(1)   操作。如果必须增加容量以适应新的容量   element,此方法成为O(n)操作,其中n为Count。

如果您使用的是Framework 3.5或更高版本,则可以使用HashSet<T>代替具有虚拟值的字典:

public void DistinctWords(String s) {
  HashSet<string> d = new HashSet<string(s.split(" "));
}