这里我有两个插入排序算法。我很难找到这两种形式的插入排序的大O.我有一个迭代形式和一个递归形式。我错误地说迭代形式是n ^ 2并且递归形式是n ^ 2。如果我错了,他们是什么,为什么?你是怎么回答这个问题的?
public void iterativeSort(int[] list) {
start = System.currentTimeMillis();
for (int i = 1; i < list.length; i++) {
count++;
int temp = list[i];
int j;
for (j = i - 1; j >= 0 && temp < list[j]; j--) {
list[j + 1] = list[j];
}
list[j + 1] = temp;
finish += System.currentTimeMillis() - start;
}
}
public static void recursiveSort(int array[], int n, int j) {
finish += System.currentTimeMillis() - start;
start = System.currentTimeMillis();
if (j < n) {
int i;
count++;
int temp = array[j];
for (i = j; i > 0 && array[i - 1] > temp; i--) {
array[i] = array[i - 1];
}
array[i] = temp;
recursiveSort(array, n, j + 1);
}
}
答案 0 :(得分:3)
是的,你是对的,两个实现都花费O(n^2)
时间。您不可能通过从递归实现切换到迭代实现来减少算法的运行时间,反之亦然。但是,对于空间使用,不会保留。
如何确定运行时间为O(n^2)
。迭代解决方案更容易,更明显。通常,当您嵌套for
- 循环而没有任何特定的中断条件并且您正在运行一小部分线性元素时,运行时间是二次的。让我们进一步分析吧。 for (int i = 1; i < list.length; i++)
中的条件评估为true
的次数是多少?答案是n-1
,因为你从第二个元素开始直到结束。例如,如果n=5
,则true
的条件为i = 1, 2, 3, 4
(由于基于0的索引),恰好n-1
次,在此示例中表示为4.现在如何很多时候内循环条件会评估为true
吗?在第一次运行时,它将被执行一次,因为i = 1
和j = 0
并且在一次迭代j
之后将-1
将打破条件。在第二次迭代中,它将被执行两次,在第三次三次等,直到n - 1
次。所以我们基本上得到的是总和1 + 2 + 3 + ... + (n - 1)
,你很容易证明它等于(n-1)n/2)
。由于您在big-O中删除常量,因此运行时间为O(n^2)
。
现在由于递归,对第二个实现的分析可能看起来有点复杂,但它实际上并没有太大的不同。内循环的逻辑for (i = j; i > 0 && array[i - 1] > temp; i--)
几乎相同,因为它执行一次,j = 1
时执行,j = 2
时执行两次等。我们将递归调用该方法多少次?再次n - 1
次,因为第一次调用是j = 1
,因此j < n
(假设n很大),然后调用recursiveSort(array, n, j + 1);
。现在j = 2
再次小于n
,因此我们会递归调用该函数直到j == n
,因此恰好n - 1
次。鉴于内部循环嵌套在O(n)
中,我们得到相同数量的迭代,即1 + 2 + 3 + ... + ( n-1 )
再次导致O(n^2)
。
所以我们非正式地证明了这两种算法具有相同的渐近运行时间。在这种情况下,我们可以认为它们相同吗否即可。这是因为每个递归调用都会在堆栈上保留额外的空间,这意味着递归解决方案占用O(n)
空间,而迭代求解O(1)
。从这个意义上讲,我们可以说迭代解决方案更好,通常就是这种情况,但递归解决方案可能更具可读性(这不是这种情况)。