算法分析:我是不是正确分析了这些算法?如何解决此类问题[关闭]

Posted

技术标签:

【中文标题】算法分析:我是不是正确分析了这些算法?如何解决此类问题[关闭]【英文标题】:Algorithm analysis: Am I analyzing these algorithms correctly? How to approach problems like these [closed]算法分析:我是否正确分析了这些算法?如何解决此类问题[关闭] 【发布时间】:2012-07-13 19:29:00 【问题描述】:

1)

  x = 25;
    for (int i = 0; i < myArray.length; i++)
    
        if (myArray[i] == x)
            System.out.println("found!");
    

我认为这个是 O(n)。

2)

for (int r = 0; r < 10000; r++)
    for (int c = 0; c < 10000; c++)
        if (c % r == 0)
            System.out.println("blah!");

我认为这个是 O(1),因为对于任何输入 n,它将运行 10000 * 10000 次。不确定这是否正确。

3)

a = 0
for (int i = 0; i < k; i++)

    for (int j = 0; j < i; j++)
        a++;

我认为这个是 O(i * k)。我真的不知道如何解决这样的问题,因为内部循环受到外部循环中递增的变量的影响。这里的一些关键见解将不胜感激。外循环运行 k 次,内循环运行 1 + 2 + 3 + ... + k 次。所以这个总和应该是 (k/2) * (k+1),这将是 k^2 的顺序。那么它实际上是O(k ^ 3)吗?这似乎太大了。同样,不知道如何处理。

4)

int key = 0;    //key may be any value
int first = 0;
int last = intArray.length-1;;
int mid = 0;
boolean found = false;

while( (!found) && (first <= last) )

    mid = (first + last) / 2;

    if(key == intArray[mid]) 
        found = true;
    if(key < intArray[mid])
        last = mid - 1;
    if(key > intArray[mid]) 
        first = mid + 1;

这个,我认为是 O(log n)。但是,我得出这个结论是因为我相信这是一个二分搜索,而且我从阅读中知道运行时间是 O(log n)。我认为这是因为对于循环的每次迭代,您将输入大小除以 2。但是,我不知道这是否是正确的推理,或者如何处理我没有见过的类似算法,并且能够以更可验证或更正式的方式推断它们在对数时间内运行。

5)

int currentMinIndex = 0;

for (int front = 0; front < intArray.length; front++)

    currentMinIndex = front;

    for (int i = front; i < intArray.length; i++)
    
        if (intArray[i] < intArray[currentMinIndex])
        
            currentMinIndex = i;
        
    

    int tmp = intArray[front];
    intArray[front] = intArray[currentMinIndex];
    intArray[currentMinIndex] = tmp;

我对此感到困惑。外循环运行 n 次。内部 for 循环运行 n + (n-1) + (n-2) + ... (n - k) + 1 次?那是 O(n^3) 吗?

【问题讨论】:

3) 是 O(k^2),因为您将执行 k*(k+1)/2 个操作,即 O(k^2)。 5) 是一样的:内循环运行 n,然后 n-1,然后 n-2 ... 然后 1 次,所以总体 n*(n+1)/2 次,所以 O(n^2)。 5) 是冒泡排序 (en.wikipedia.org/wiki/Bubble_sort),即 O(n^2)。 你能详细说明一下吗?内循环不运行 n*(n+1)/2 次吗?并且外部循环不会运行 n 次。那不是 [ n * ( n*(n+1)/2) ] @ordinary:检查我的答案,重要的是你执行比较的次数,所以它只是内循环运行的总次数,即 n*(n+1)/ 2 【参考方案1】:

或多或少,是的。

1 是正确的 - 似乎您正在搜索我认为是未排序集合中的特定元素。如果是这样,最坏的情况是该元素位于列表的最后,因此 O(n)。

2 是正确的,虽然有点奇怪。假设 rc 是常量并且边界不是变量,则为 O(1)。如果它们是恒定的,那么是 O(1),因为没有什么可输入的。

3 我相信这仍然被认为是 O(n^2)。会有一些常数因子,如 k * n^2,去掉常数,你得到 O(n^2)。

4 看起来很像排序集合的二进制搜索算法。 O(logn) 是正确的。它是日志,因为在每次迭代中,您基本上将您要查找的元素所在的可能选择数量减半。

5 看起来像冒泡排序,O(n^2),原因与 3 类似。

【讨论】:

你能看到第 3 点吗,可以是 O(n^2)。怀疑因为内循环将迭代到外循环的 0.5 倍,所以它不完全是 O(n^2)。 @PunithRaj ,对于第 3 点 - 如果您将外循环视为 O(n),将内循环视为 O(n/2)。那么我们应该将其视为O(n ^ 2)。根据大 O O(n/2) 是 O(n)。因为 n/2 基于输入“n”线性增加。例如。如果 n = 100,则 n/2 = 50。如果 n= 10000,则 n/2 = 5000 等等。【参考方案2】:

O() 本身没有任何意义:您需要指定是计算“最坏情况”O 还是平均情况 O。对于某些排序算法,它们有 O(n log n ) 平均而言,但在最坏的情况下为 O(n^2)。

基本上你需要计算最内层循环的总迭代次数,并在没有任何常数的情况下取结果的最大分量(例如,如果你有 k*(k+1)/2 = 1/2 k ^2 + 1/2 k,最大的分量是 1/2 k^2 因此你是 O(k^2))。

例如,您的项目 4) 在 O(log(n)) 中,因为如果您处理大小为 n 的数组,那么您将在该数组上运行一次迭代,下一次将在数组上运行大小为 n/2,然后是 n/4,...,直到这个大小达到 1。所以它是 log(n) 次迭代。

【讨论】:

不,还有 theta 和 .. 最好和一般情况下的其他东西。大 O 总是最坏的情况。 同意 theta 表示法,尽管许多人使用 O 表示一般情况;快速排序通常被称为 O(n log n)...【参考方案3】:

您的问题主要是关于 O() 的定义。

当有人说这个算法是 O(log(n)) 时,你必须阅读:

当输入参数n变得很大时,算法执行的操作数最多增长log(n)

现在,这意味着两件事:

    您必须至少有一个输入参数 n。没有一个就谈论 O() 是没有意义的(就像你的情况2一样)。 您需要定义正在计数的操作。这些可以是添加,两个元素之间的比较,分配的字节数,函数调用的数量,但你必须决定。通常您会采取对您来说成本最高的手术,或者如果做太多次就会变得昂贵的手术。

记住这一点,回到你的问题:

    n 是 myArray.Length,您计算的操作数是 '=='。在这种情况下,答案正好是 n,即 O(n)

    你不能指定一个 n

    n只能是k,你算的操作数是++。正如您所说,您恰好有 k*(k+1)/2,即 O(n2)

    这次n又是你数组的长度,你算的操作是==。在这种情况下,操作的数量取决于数据,通常我们谈论“最坏情况”,意思是在所有可能的结果中,我们看最耗时的那个。该算法充其量只进行一次比较。对于最坏的情况,让我们举个例子。如果数组是 [[1,2,3,4,5,6,7,8,9]] 并且您正在寻找 4,您的 intArray[mid] 将依次变为 5、3 和 4,依此类推您将进行 3 次比较。实际上,对于一个大小为 2^k + 1 的数组,最大比较次数为 k (可以查看)。所以 n = 2^k + 1 => k = ln(n-1)/ln(2)。您可以将此结果扩展到 n 不 = 2^k + 1 的情况,您将得到复杂度 = O(ln(n))

无论如何,我认为您很困惑,因为您不完全了解 O(n) 的含义。我希望这是一个开始。

【讨论】:

以上是关于算法分析:我是不是正确分析了这些算法?如何解决此类问题[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

我的堆排序算法时间复杂度分析是不是正确?

可达性分析算法(根搜索算法GCRoots)

3.4 网页分析算法

matlab基于人工蜂群算法的函数优化分析matlab优化算法十一

洗牌算法分析

算法实践| 手把手带你实现快速排序算法