【问题标题】:Big O of two functions两个函数的大 O
【发布时间】:2012-05-09 17:55:50
【问题描述】:

我已经用PHP编程很长时间了,由于我不是来自计算机科学/数学背景的我对Big O符号只有一个基本的了解,所以我拿了一个函数并尝试了改进它并在大 O 中表达它们:

示例 1

function foo($j) {
    $ids = array();
    while (count($ids) < $j) {
        $id = gen_id();  // assume this function will return you an integer
        if (!in_array($id, $ids)) {
            $ids[] = $id;
        }
    }
    return $ids;
}

我将通过删除count($ids) 的while 循环并替换为forloop 来改进此功能,这样count($ids) 就不必在循环中每次都进行评估,并将is_array 替换为@ 987654327@ 并将值移动到键(isset 比 in_array 快)

示例 2 - 改进

function foo($j) {
    $ids = array();
    for($i = 1; $i<= $j; ++$j) {
        $id = gen_id();  // assume this function will return you an integer
        if (!isset($ids[$id])) {
            $ids[$id] = true;
        }
        else {
            --$i;
        }
    }
    return $ids;
}

我会用以下大 O 表示法来表达上述函数:

示例 1: O(n^2),示例 2: O(n)

我的符号正确吗?是否还有更好的方法来执行相同的功能?

提前致谢!

【问题讨论】:

  • 首先,你确定这个方法首先需要优化吗?其次,两者的正确表示法是O(n)(常量因子与大 O 表示法无关)。
  • 您可能指的是第二个 for 循环中的 ++$i
  • 是的,它应该是 $i.. 但是 --$i;
  • @Lizard 我以更简洁的方式重写了您的函数并将其发布为答案。我认为您无法获得比我的答案更有效的结果。 :)
  • 谢谢!现在这真的很有意义!

标签: php performance optimization big-o


【解决方案1】:

下面是我将如何以更直接的方法编写该函数:内部for 循环是do ... while 循环的完美场景。

function foo( $j)
{
    $ids = array();
    for( $i = 0; $i < $j; $i++)
    {
        do
        {
            $id = gen_id();
        } while( isset( $ids[$id]));
        $ids[$id] = true;
    }
    return $ids;
}

编辑: 实际上,这个函数是O($j) / O(n),因为gen_id()isset() 都是常量O(1)isset() 是一个哈希表查找)。所以,for 循环的内部效率是常数时间O(1),使得整个函数O(n)

【讨论】:

  • 我知道 isset 是一个哈希表查找,因此 O(1)。是 for 循环使它成为 O(n) 吗?
  • 是的,for 循环是 O(n) 的原因,因为它(for 循环)必须进行 n 次迭代才能生成 n 个 ID。
  • 谢谢,这现在开始变得更清楚了......但无论哪种方式,第二个函数都更快,即使两者都是 O(n),因为示例 1 有 O(n) + O(n)第二个是 O(n) + O(1)?
  • 第一个其实是O(n^2),因为while循环会执行n次,而in_array的调用是线性搜索,使得while循环里面的代码O(n),所以是O(n) * O(n) = O(n^2)
  • 谢谢!现在这真的很有意义!
【解决方案2】:

首先:常数系数在大 O 表示法中无关紧要,这意味着 O(n) = O(cn) 对于任何常数 c != 0

对于第一个,我知道count($ids) 需要O(1) 时间来评估,但是in_array($id, $ids) 怎么样?我不确切知道。但如果是O(n)O(logn),那么整体将是O(n^2)O(nlogn)。我不认为这可以在O(1) 时间实现,这可能会为整个函数提供O(n) 时间。

对于第二个,这是O(n),似乎比第一个快。

编辑:我只是认为维基百科已经以某种方式清楚地描述了the big O notation。去读一些吧。

【讨论】:

  • 仅供参考,in_arrayO(n),因为它执行线性搜索。
【解决方案3】:

你的想法很好,但你不正确。

下面将为您澄清....

function foo($j) 
{
 for($i=1;$i<j;$i++)
 {
  // some code here
 }
 for($i=1;$i<j;$i++)
 {
 // some code here
 }
}

您可能认为这将是 0(2n),但常数项并未以 0 表示法表示。所以 它的复杂度为 0(n)。

看下面

 function foo($j) 
{
 for($i=1;$i<j;$i++)
 {
    for($k=1;$k<i;$k++)
    {
     // some code here
    }
 }

}

复杂度为0(n^2)。

【讨论】:

    【解决方案4】:
    for ($i=0;$i<$j; ) {
      $id = gen_id();
      if (!isset($ids[$id])) {
        $ids[$id]=true;
        $i++;
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多