【问题标题】:Why this loop backwards is much slower than going forward?为什么这个循环向后比向前慢得多?
【发布时间】:2012-06-06 21:55:39
【问题描述】:

我在这里回答了另一个人的问题How to count string occurrence in string? 所以我在玩算法here,在对一些函数进行基准测试后,我想知道为什么向后循环比向前循环慢得多。

Benchmark test here


注意:下面的代码不能正常工作,有 其他有效的(这不是这个问题的重点),请注意 复制前>粘贴

转发

function occurrences(string, substring) {

  var n = 0;
  var c = 0;
  var l = substring.length;

  for (var i = 0, len = string.length; i < len; i++) {

    if (string.charAt(i) == substring.charAt(c)) {
      c++;
    } else {
      c = 0;
    }

    if (c == l) {
      c = 0;
      n++;
    }
  }
  return n;
}

向后

function occurrences(string, substring) {

  var n = 0;
  var l = substring.length - 1;
  var c = l;

  for (i = string.length; i > 1; i--) {

    if (string.charAt(i) == substring.charAt(c)) {
      c--;
    } else {
      c = l;
    }

    if (c < 0) {
      c = l;
      n++;
    }
  }
  return n;
}

【问题讨论】:

标签: javascript performance loops


【解决方案1】:

我认为向后测试有一个错误:

for (i = string.length; i &gt; 1; i--) {

应该是

for (i = string.length - 1; i &gt;= 0; i--) {

istring.length 时,string.charAt(i) 未定义。这样做几千次,可能会产生很大的不同。

Here's a modified test 似乎产生更接近相同的性能。

【讨论】:

  • 你对i&gt;=0 是正确的,但对未定义的却不是,因为我只是没有走到字符串的开头,也没有检查位置 0 的字符。谢谢,但这不是原因瓶颈。
  • 我发现了问题,所以我自己回答了。
【解决方案2】:

我自己找到了瓶颈。

当我这样做时

for (i = string.length; i > 1; i--) {

我不小心从var i 中删除了“var”,所以我将i 设为全局。 修复后我得到了预期的结果。

for (var i = string.length; i > 1; i--) {

我从来没有想过这可能是一个巨大的差异,所以要注意伙计们。

Fixed Benckmark test here

之前:

之后:

PS:实际使用,请勿使用此功能,indexOf 版本要快得多。

【讨论】:

    【解决方案3】:

    您使用什么数据进行测试。如果您的数据有很多匹配的前缀,但反过来却没有很多错误匹配,那可能会影响它。

    也不会像“aaabbaaa”这样的搜索错误尝试找到“aab”,它将匹配aa,然后失败,然后从第三个a继续并失败。 ?

    【讨论】:

    • 两个函数都使用相同的输入,但你的例子对我来说没有意义。无论如何,您在aaabbaaaaab 上总是只能获得一场比赛。
    • 是的,您应该这样做,但在我看来,第一个代码在 aaabbaaa 中找不到 aab 的匹配项。
    • 它会去:Aaabbaaa AAabbaaa AAAbbaaa (FAIL) 然后继续将 aaaBbaaa 匹配到 Aab (FAIL) 并且不会匹配。
    • 我会研究正则表达式匹配器和有限状态机。 ;) 生成一个简单的 DFA 通常是匹配内容的最快方法,尤其是如果您可以将其直接编译为字节码,而字节码会被 jitted。
    • 那个新的可能会工作,但我不确定它是否比正确的 DFA 或 NFA 更快,因为您有长时间的错误匹配。
    【解决方案4】:

    由于它们不是完整的镜像函数,所以在两个函数的所有ifs 和elses 中添加console.log()s 并比较结果,您会发现测试不公平。

    你做错了什么。我建议在开始测试之前确保它们都按预期工作。

    【讨论】:

    • 不,它们是等价的,是相同的逻辑,我从两者得到相同的输出。
    猜你喜欢
    • 2017-01-29
    • 1970-01-01
    • 2019-09-29
    • 1970-01-01
    • 2013-08-05
    • 1970-01-01
    • 2014-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多