任何人都可以解释以下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 是字典中的键数。这是对的吗?
答案 0 :(得分:27)
它写在Dictionary ...
的文档中Dictionary泛型类提供从一组键到一组值的映射。字典的每个添加都包含一个值及其关联的键。通过使用其键来检索值非常快,接近于O(1),因为Dictionary类是作为哈希表实现的。
对于Add函数:
如果Count小于容量,则此方法接近O(1)操作。如果必须增加容量以容纳新元素,则此方法将成为O(n)操作,其中n为Count。
答案 1 :(得分:13)
这两种方法都有不变的复杂性:
答案 2 :(得分:11)
这个例程总体上是O(m)时间复杂度,m是搜索中的字符串数。
这是因为Dictionary.Contains和Dictionary.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(" "));
}