【问题标题】:Is number comparison faster than string comparison?数字比较比字符串比较快吗?
【发布时间】:2013-05-06 09:44:16
【问题描述】:

我听说散列(即将字符串或对象转换为数字)用于字符串等,因为它比字符串更容易比较数字。如果属实,这是什么原因?

【问题讨论】:

  • 我有一个预感 - john = 12, johnny = 5. 12 = 1100 in binary 5 = 0101. 比较数字(转换为二进制后)要快得多。比较 -john- 的 4 个字符(每个字符都有自己的二进制代码),然后意识到它们不一样。但是,如果名称以不同的字母开头,则散列将无济于事。说得通 ?我不确定它是否正确。
  • 就占用多少内存而言,字符串往往比您通常使用的数字大得多,比较字符串的标准方法是查看它们是否相同大小,如果所以,比较他们的记忆,看看它是否在任何地方都不同。简单的“原始”整数类型可以存储为 2s 补码压缩位:缺点是它们只能在 32 位空间中存储(例如)-20 亿到 20 亿(左右)的值,但具有优势相比之下,内存要少得多。这些整数比较通常也在单个处理器周期内完成。

标签: java c++ computer-science


【解决方案1】:

不一定是这样,但可能大部分时间都是这样。

考虑以下情况:

我想比较字符串“apples”和“oranges”。如果我只想确定 "apples" == "oranges",我只需要比较每个字符串的第一个字符:'a' != 'o' => "apples" != "oranges"。如果我对字符串进行哈希处理然后进行比较,则速度会明显变慢,因为我必须在比较结果整数之前解析两个字符串并将它们输入哈希算法。

但是,如果我需要多次进行此比较,并且可能我经常将“橙子”与“猩猩”进行比较,那么如果我对所有字符串进行一次哈希处理并多次比较整数,它会工作得更快。这就是哈希映射所基于的原理。

但是请注意,散列字符串对于直接等于比较很有用,它无法确定字符串在字典上是否大于或小于彼此,因此无法通过散列方法对字符串进行排序。 (这就是为什么 Java 中的 HashMap 是无序的)。

【讨论】:

    【解决方案2】:

    比较两个数字比比较两个字符串(表示相同的数字)要快很多。比较两个数字只需要比较各个位,并且可以使用 AND、XOR、2 的补码等中的任何一种来超快速地完成。

    比较两个字符串非常缓慢且昂贵。大多数算法需要遍历整个字符串并匹配每个字符。

    例如,假设我们想比较 9 和 12(假)。对于数字比较,我们假设算法比较单个位。 9 = 1001 12 = 1100

    这里,最坏情况算法将比较 4 位

    现在如果我们将“9”和“12”表示为字符串,它们将分别以 16 位存储在内存中(回想一下:Java 使用 UTF-16 表示内存中的字符串)并且必须传递给字符串比较算法。其实Java实际的String比较函数如下:

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = count;
            if (n == anotherString.count) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = offset;
                int j = anotherString.offset;
                while (n-- != 0) {
                    if (v1[i++] != v2[j++])
                        return false;
                }
                return true;
            }
        }
        return false;
    }
    

    如您所见,字符串比较还有很多内容。

    【讨论】:

    • 我也喜欢你的回答。请告诉我这个 anotherString.count 是什么?我在 API 的任何地方都没有看到 .count。你的意思是 String.length() 吗?
    • 我想这里最大的问题是循环。但是在比较数字的位时不也存在循环吗?
    【解决方案3】:

    比较原始数字肯定比比较字符串快,因为它只是一条计算机指令,而在 Java 中比较字符串是一种方法。但是在 Java 中使用散列是出于不同的原因,Object.hashCode() 用于散列表中以便在集合中快速搜索。

    【讨论】:

      【解决方案4】:

      一般来说,大多数计算机都有一条指令来比较整数、长整数等 最多需要几个指令周期。字符串通常由实用函数/方法进行比较(此规则可能存在奇怪的例外)。

      例如,在 Java 中,字符串基本上表示为

           /** The value is used for character storage. */
           private final char value[];
      
           /** The offset is the first index of the storage that is used. */
           private final int offset;
      
           /** The count is the number of characters in the String. */
           private final int count;
      

      而equals方法是

      if (this == anObject) {
          return true;
      }
      if (anObject instanceof String) {
          String anotherString = (String)anObject;
          int n = count;
          if (n == anotherString.count) {
              char v1[] = value;
              char v2[] = anotherString.value;
              int i = offset;
              int j = anotherString.offset;
              while (n-- != 0) {
                  if (v1[i++] != v2[j++])
                      return false;
              }
              return true;
          }
      }
      return false;
      

      equals 方法同时执行 this == anObjectn == anotherString.count,两者本质上都是整数比较,甚至在它开始比较字符之前。这将比整数比较花费的单个指令花费更长的时间


      C 字符串比较比 Java 等价物更简单/更快,但它将包含某种循环和每次通过循环的多条指令。

      这将比整数比较所需的一条指令花费更长的时间

      【讨论】:

        【解决方案5】:

        是的,但这与散列无关。

        比较数字涉及比较位的简单硬件指令。

        比较字符串涉及 (a) 遍历两个字符串,直到找到不同的字符(与固定大小的数字不同)和 (b) 大量 Unicode 魔法(不同长度的不同字符串实际上可以相等,并且不同的字符在不同的代码块中比较不同)。


        散列通常用于将字符串转换为数组索引。

        【讨论】:

        • 我有预感 - john = 12, johnny = 5. 12 = 1100 in binary 5 = 0101. 比较数字(转换为二进制后)比。比较 -john- 的 4 个字符(每个字符都有自己的二进制代码),然后意识到它们不一样。但是,如果名称以不同的字母开头,则散列将无济于事。说得通 ?我不确定它是否正确。
        • 由于可能的字符串组合比平均字符串容量多得多,因此您将有很多匹配相同数字的字符串,因此您必须检查它们是否匹配,如果匹配,请执行真正的责备。此外,你打破了 SLaks 提到的所有 unicode 问题。
        • @SLaks 我怀疑你的大多数数字都是固定大小的。 :) Bignums 将需要迭代,并且比较花哨的“数字”(惰性求值、符号计算、实数等)可能相当昂贵。但更严重的是,在什么世界里“散列”一个将字符串转换为数组索引的术语?
        • @Yakk:散列用于将字符串转换为数组索引(用于散列表)
        • @SLaks 哈希可以用作该过程中的一个步骤,是的。这不是散列的唯一目的。
        猜你喜欢
        • 2014-07-13
        • 2013-02-12
        • 2011-06-21
        • 2012-02-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多