我试图找到o符号的限制,我想知道是否有一个简单的例子演示了对任务的启用,其中版本1与版本2相同,但版本2在更高效后工作增强
感谢
答案 0 :(得分:6)
在下面的代码中,在// do something
之后添加一行来突破内部循环会留下更快的函数,但仍然是一个O(n ^ 2)。
for (int i = 0; i < n; i++) {
for (int j = 0; i < n; j++) {
if (i == j) {
// do something
}
}
}
答案 1 :(得分:3)
O表示法描述了函数的限制行为,算法的最坏情况。通常,对于同一任务比较不同的算法就足够了,比如通过该函数对算法进行排序。
我会说,对于几乎所有的算法(O(1)算法除外)),总会有一些输入数据使算法在更短的时间内终止(或者用更少的内存消耗),然后用描述的O表示法表示那个算法。
假设我们有一个类似的计数算法:
private int counter(int n) {
int counter;
for (int i = 0; i < 2; i++) {
counter = 0;
for (int i = 0; i < n; i++) {
counter++;
}
}
return counter;
}
增长是线性的,所以这个计数器的O表示法是O(n)(我只看步骤,而不是记忆)。你可以说,嘿,我们计算两次,然后写O(2n)。真正。您甚至可以编写O(2n + c)来表示我们需要一些额外的步骤(时间)来创建和初始化局部变量。
这是一个改进的实现,仍然是线性的(O(n)),但终止速度明显更快:
private int counter(int n) {
int counter =0;
for (int i = 0; i < n; i++) {
counter++;
}
return counter;
}
两者都可以描述为O(n)以指示线性增长。这可能就足够了,例如将这些实现与该计数器的O(n ^ 2)或O(1)实现进行比较。但是为了比较'线性'版本A和B,我们需要更精确,并将第一个识别为O(2n),将第二个识别为O(n)。现在,O符号值的比较给出了预期的结果:实现B是“更好”。
答案 2 :(得分:0)
此合并排序代码在nLog(n)中起作用:
/**
* Mergesort algorithm.
* @param a an array of Comparable items.
*/
public static void mergeSort( Comparable [ ] a ) {
Comparable [ ] tmpArray = new Comparable[ a.length ];
mergeSort( a, tmpArray, 0, a.length - 1 );
}
/**
* Internal method that makes recursive calls.
* @param a an array of Comparable items.
* @param tmpArray an array to place the merged result.
* @param left the left-most index of the subarray.
* @param right the right-most index of the subarray.
*/
private static void mergeSort( Comparable [ ] a, Comparable [ ] tmpArray,
int left, int right ) {
if( left < right ) {
int center = ( left + right ) / 2;
mergeSort( a, tmpArray, left, center );
mergeSort( a, tmpArray, center + 1, right );
merge( a, tmpArray, left, center + 1, right );
}
}
/**
* Internal method that merges two sorted halves of a subarray.
* @param a an array of Comparable items.
* @param tmpArray an array to place the merged result.
* @param leftPos the left-most index of the subarray.
* @param rightPos the index of the start of the second half.
* @param rightEnd the right-most index of the subarray.
*/
private static void merge( Comparable [ ] a, Comparable [ ] tmpArray,
int leftPos, int rightPos, int rightEnd ) {
int leftEnd = rightPos - 1;
int tmpPos = leftPos;
int numElements = rightEnd - leftPos + 1;
// Main loop
while( leftPos <= leftEnd && rightPos <= rightEnd )
if( a[ leftPos ].compareTo( a[ rightPos ] ) <= 0 )
tmpArray[ tmpPos++ ] = a[ leftPos++ ];
else
tmpArray[ tmpPos++ ] = a[ rightPos++ ];
while( leftPos <= leftEnd ) // Copy rest of first half
tmpArray[ tmpPos++ ] = a[ leftPos++ ];
while( rightPos <= rightEnd ) // Copy rest of right half
tmpArray[ tmpPos++ ] = a[ rightPos++ ];
// Copy tmpArray back
for( int i = 0; i < numElements; i++, rightEnd-- )
a[ rightEnd ] = tmpArray[ rightEnd ];
}
答案 3 :(得分:0)
无法反驳部分问题吗?因此,采用流畅运行的版本,使其效率更低,但不会改变原始代码的大O.例如,添加一行以使程序在执行某些工作时休眠10秒是一个恒定的时间变化,在计算big-O时会被删除,我想。在这种情况下,带有额外代码的版本将是版本1,而另一个版本是版本2,它更有效但是无关紧要。
如果有人想要更抽象的答案,因为big-O忽略低阶项和常数乘数,这些可以是在不改变方法的整体大O的情况下可以提高效率的地方。对不起,这里没有任何Java代码,但这个答案与语言无关。