【问题标题】:Time complexity of PHP's explode/implodePHP的explode/implode的时间复杂度
【发布时间】:2012-12-28 23:39:12
【问题描述】:

如果知道 PHP 用于爆炸/内爆函数的算法以及它们的时间复杂度是多少,我很感兴趣?

提前谢谢你。

【问题讨论】:

  • O(N),我想。我看不出你怎么能做得更好或更糟。
  • @KamilTomšík- 这对于在大型数据集上进行大量调用以爆炸/内爆的程序来说可能非常重要。如果函数是超线性的,那么尝试在大型程序中使用这些函数将是一个非常糟糕的主意,并且 OP 最好重新实现它们以更快。如果它们在某种程度上是次线性的,那么很高兴知道,因为值得重写代码以尝试更频繁地使用爆炸/内爆。
  • @KamilTomšík 我需要知道使用explode 的程序的运行时间。就这么简单。

标签: php algorithm time-complexity


【解决方案1】:

string.c 你可以看到算法。它开始于大约1021 line..

    if (p2 == NULL) {
    add_next_index_stringl(return_value, p1, Z_STRLEN_P(str), 1);
    } else {
    do {
        add_next_index_stringl(return_value, p1, p2 - p1, 1);
        p1 = p2 + Z_STRLEN_P(delim);
    } while ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) != NULL &&
             --limit > 1);

    if (p1 <= endp)
        add_next_index_stringl(return_value, p1, endp-p1, 1);
    }

它只是一个循环所以我称之为它有O(N) 复杂度。并仔细检查代码。它扫描字符串并将结果添加到return_value。所以是的。 它是线性的

【讨论】:

  • 一个简单的问题 - Z_STRLEN_P 的复杂性是什么?如果这不是 O(1),那么复杂度可能会更准确地为 O(mn),其中 n 是字符串长度,m 是分隔符的长度。
  • @templatetypedef 即O(1)。因为delim 是一个zval 而这个宏指向(zval).value.str.val
【解决方案2】:

简答:对于单字节分隔符,explode 的时间复杂度为Ο(N‍);但是对于多字节分隔符,它的时间复杂度是Ο(N2)。

implode 显然在 Ο(N‍) 中,因为它只是将各个部分粘合在一起。

扩展答案:basic algorithm of explode 是在 string 中搜索出现的 delimiter 并将包含的子字符串复制到一个新数组中。

为了在字符串中查找分隔符的位置,它使用internal function zend_memnstrphp_memnstr只是zebd_memnstr的别名)。对于单个字节,它只调用 memchr 进行线性搜索(因此在 Ο(N) 中)。

但是对于超过一个字节的delimiter值,它会调用memchrstring中搜索delimiter的第一个字节的位置,测试 delimiter 的最后一个字节是否出现在 string 中的预期位置,并调用 memcmp 来检查其间的字节。所以它基本上检查 delimiter 是否包含在 string 中的任何可能位置。这听起来有点像Ο(N2)。

现在让我们看一下该算法的最坏情况,其中模式的第一个和最后一个字节都适合,但倒数第二个不适合,例如:

string:     aaaabaaaa
delimiter:  aaaaaa

aaaabaaaa
aaaaXa      (1+1+5)
 aaaX?a     (1+1+4)
  aaX??a    (1+1+3)
   aX???a   (1+1+2)

X 表示 memcmp? 未知字节不匹配。括号中的值是统一度量的时间复杂度。这将总结为

Σ (2+i) for iM-floor(N/2) 到 ceil (N/2)

(N-‍M+1)·2 + Σ i - Σ j for i 从 1 到 ceil(N/2), j 从 1 到 M-floor(N/2)-1.

由于 Σ i for i 从 1 到 N 可以表示为 N·( N+1)/2 = (N2+N)/2,我们也可以写成:

(N-‍M+1)·2 + (ceil(N/2)2 +ceil(N/2))/2 - ((M-floor(N/2)-1)2+(M-floor(N/2)-1))/2

为简单起见,我们假设 NM 总是偶数,所以我们可以省略 'ceil's 和 'floor's:

(N-‍M+1)·2 + ((N/2+1)2+N/2+1)/2 - ((M-‍N/2-1)2+(M-‍N/2)-1)/2
= (N-‍M+1)·2 + N2/8+3· N/4+1 - ((M-‍N/2-1)2+(M-‍N/2)-1)/2

此外,我们可以向上估计值:N-‍M N和M-‍ N/2-1 N。因此我们得到:

N·2 + N2/8+3·N/4+1 - (N2+N)/2
N·2 + N2+4·N - N2+N

这证明具有多个字节分隔符的explode 在Ο(N2) 中。

【讨论】:

    【解决方案3】:

    根据 GitHub 上的 PHP 源代码,它是线性的。你可以查看explode()here

    【讨论】:

      猜你喜欢
      • 2011-11-27
      • 1970-01-01
      • 2013-05-22
      • 1970-01-01
      • 1970-01-01
      • 2020-02-03
      • 2011-08-04
      • 2016-02-13
      • 2012-08-14
      相关资源
      最近更新 更多