【发布时间】:2013-08-13 20:22:28
【问题描述】:
如果我理解大 O 表示法,并且相信我在这一点上的理解可能远低于大多数人,以下代码行是 O(n2) 根据 Keyser 的评论,这实际上已经是一个 O(n) 操作:
"Hello, World!".ToLower().Contains("a");
因为ToLower() 是O(n) 操作,Contains 也是。可能是O(n + n),再说一遍,我的理解还是很模糊。
注意:下面列出了在 Release 构建中运行的测试方法,并利用 Stopwatch 类跟踪运行时间。
但是,我想让它更快,因此请考虑以下三种测试方法:
private static void TestToLower(int i)
{
var s = "".PadRight(i, 'A');
var sw = Stopwatch.StartNew();
s.ToLower().Contains('b');
sw.Stop();
_tests.Add(string.Format("ToLower{0}", i), sw.ElapsedMilliseconds);
}
private static void TestHashSet(int i)
{
var s = "".PadRight(i, 'A');
var sw = Stopwatch.StartNew();
var lookup = new HashSet<char>(s.ToLower().AsEnumerable());
lookup.Contains('b');
sw.Stop();
_tests.Add(string.Format("ToHashSet{0}", i), sw.ElapsedMilliseconds);
}
private static void TestHashSet2(int i)
{
var s = "".PadRight(i, 'A');
var sw = Stopwatch.StartNew();
var lookup = new HashSet<char>(s.ToLower().ToArray());
lookup.Contains('b');
sw.Stop();
_tests.Add(string.Format("ToHashSet2{0}", i), sw.ElapsedMilliseconds);
}
现在考虑执行这样的操作:
TestToLower(1000000);
TestToLower(2000000);
TestToLower(4000000);
TestHashSet(1000000);
TestHashSet(2000000);
TestHashSet(4000000);
TestHashSet2(1000000);
TestHashSet2(2000000);
TestHashSet2(4000000);
结果如下:
ToLower1000000: 22.00 ms
ToLower2000000: 40.00 ms
ToLower4000000: 84.00 ms
ToHashSet1000000: 48.00 ms
ToHashSet2000000: 73.00 ms
ToHashSet4000000: 145.00 ms
ToHashSet21000000: 58.00 ms
ToHashSet22000000: 107.00 ms
ToHashSet24000000: 219.00 ms
他们每个人显然仍然必须使用ToLower 方法,但我正在尝试使用HashSet 来加快查找速度。理想情况下,您不必扫描整个字符串。此外,我真的认为第二个整体测试TestHashSet 会更快,因为它不必创建大量内存来分配HashSet。
回想起来,我认为为什么最后两种方法较慢。我相信它们更慢,因为我有与第一个相同的算法(即我必须至少遍历整个字符串两次),但除此之外,我还在进行查找。
我怎样才能使这个算法更快?我们经常使用它,我们必须不分大小写地比较字符串。
【问题讨论】:
-
连续做两个独立的
O(n)操作确实是O(n+n)也就是O(n)。思考过程是这样的:相对于n或n^2,迭代次数是否增加? -
@Keyser,所以唯一更快的操作是
log(n)?如果是这样,那log到底是什么意思,因为我显然不明白n+n是n。 -
Big O "math" 声明 O(n+n) 等价于 O(n)
-
@TheSolution 我建议阅读算法复杂性度量的介绍。 n+n 不是 n,但 O(n+n) 与 O(n) 相同。
-
对于初学者,请确保您的基准测试反映了您的用例。你真的每个“干草堆”字符串只搜索一次,你的字符串真的很大吗(以百万字节为单位)?如果您多次搜索,请更改您的基准以解决此问题(通过重新使用您从字符串构建的任何数据结构)。如果您的字符串更小,请缩小您的测试字符串以更接近真实交易(如果结果太快,则多次运行一次)。