所以我想我会因为提出这样一个微不足道的问题而被埋葬,但我对某些事情感到有些困惑。
我已经在Java和C中实现了quicksort,我正在做一些基本的比较。该图表以两条直线形式出现,其中C比Java对应的快了4ms,超过100,000个随机整数。
我的测试代码可以在这里找到;
我不确定(n log n)行是什么样的,但我不认为它会是直的。我只是想检查这是否是预期的结果,我不应该尝试在我的代码中找到错误。
我将公式固定在excel中,而对于10号基数,它似乎是一条直线,在开始时有一个扭结。这是因为log(n)和log(n + 1)之间的差异是线性增加的吗?
谢谢,
GAV株系
答案 0 :(得分:76)
使图表更大,你会看到O(n logn)不是一条直线。但是,是的,它非常接近线性行为。要了解原因,只需使用几个非常大的数字的对数。
例如(基数10):
log(1000000) = 6
log(1000000000) = 9
…
因此,为了对1,000,000个数字进行排序,O(n logn)排序会增加一个可测因子6(或者更多一点,因为大多数排序算法将取决于基数2的对数)。不是很多。
实际上,这个对数因子 so 非常小,对于大多数数量级,已建立的O(n logn)算法优于线性时间算法。一个突出的例子是创建后缀数组数据结构。
一个简单的案例最近咬了我when I tried to improve a quicksort sorting of short strings by employing radix sort。事实证明,对于短字符串,这个(线性时间)基数排序比快速排序快,但是对于仍然相对较短的字符串有一个临界点,因为基数排序关键取决于你排序的字符串的长度。
答案 1 :(得分:11)
仅供参考,快速排序实际上是O(n ^ 2),但平均情况为O(nlogn)
仅供参考,O(n)和O(nlogn)之间存在很大差异。这就是为什么它不能被O(n)限制为任何常数。
有关图形演示,请参阅:
答案 2 :(得分:5)
为了获得更多相似的乐趣,请尝试在标准disjoint set data structure上绘制 n 操作所花费的时间。它已被证明是渐近 n α( n ),其中α( n )是Ackermann function的倒数(尽管您通常的算法教科书可能只会显示 n 日志日志 n 或可能 n log* n )。对于您可能会遇到的任何类型的数字作为输入大小,α( n )≤5(实际上log * n ≤5),尽管它确实如此接近无穷大渐近。
我认为你可以从中学到的是,虽然渐近复杂度是一种思考算法的非常有用的工具,但它与实际效率并不完全相同。
答案 3 :(得分:3)
因此,对于少量数据,O(n * log(n))类似于线性。
提示:不要忘记快速排序在随机数据上的表现非常好,并且它不是O(n * log(n))算法。
答案 4 :(得分:2)
如果正确选择了轴,任何数据都可以在一条线上绘制: - )
维基百科说Big-O是最坏的情况(即f(x)是O(N)意味着f(x)被N“https://en.wikipedia.org/wiki/Big_O_notation
”限制在“上方”这是一组很好的图表,描述了各种常见功能之间的差异: http://science.slc.edu/~jmarshall/courses/2002/spring/cs50/BigO/
log(x)的导数是1 / x。这是log(x)随x增加的速度增加的速度。它不是线性的,虽然它可能看起来像一条直线,因为它的弯曲速度很慢。当考虑O(log(n))时,我认为它是O(N ^ 0 +),即N的最小幂不是常数,因为N的任何正恒定幂最终都会超过它。这不是100%准确,所以如果你这样解释,教授会生你的气。
两个不同碱基的对数之间的差异是常数乘数。查找在两个基数之间转换日志的公式: (在“基础变更”下:https://en.wikipedia.org/wiki/Logarithm) 诀窍是将k和b视为常数。
在实践中,您绘制的任何数据通常都会出现一些小问题。你的程序之外的东西会有所不同(在程序之前交换到cpu中的东西,缓存未命中等)。需要多次运行才能获得可靠的数据。常量是尝试将Big O表示法应用于实际运行时的最大敌人。对于足够小的N,具有高常数的O(N)算法可以比O(N ^ 2)算法慢。
答案 5 :(得分:1)
log(N)是(非常)大致N中的位数。因此,在大多数情况下,log(n)和log(n + 1)之间几乎没有区别
答案 6 :(得分:0)
尝试在它上面绘制一条实际的直线,你会看到小幅增加。请注意,50,0000处的Y值小于100,000的1/2 Y值。
它在那里,但它很小。这就是O(nlog(n))如此优秀的原因!