2013-05-12 176 views
12

我聽說散列(即將字符串或對象轉換爲數字)用於字符串等,因爲它比字符串比較容易。如果屬實,這是什麼原因?數字比較比字符串比較更快嗎?

+0

我有一個預感 - 約翰尼= 12,約翰尼= 5。12 = 1100在二進制5 = 0101.比較數字(轉換爲二進制後)比。比較4個字符-john-(每個字符都有自己的二進制代碼),然後意識到它們是不一樣的。但是,如果名稱以不同的字母開頭,那麼哈希將不會有幫助。說得通 ?我不確定它是否正確。 – 2013-05-12 02:58:57

+0

字符串往往比您通常使用的數字大得多,它們佔用的內存量多少,比較字符串的標準方法是查看它們是否大小相同,如果是,請比較它們的內存以查看如果它在任何地方都不同。簡單的「原始」整數類型可以存儲爲二進制補碼壓縮比特:這有一個缺點,即它們只能在其32位空間中存儲(例如) - 20億到20億(或大約)的值,但具有優勢比較的內存少得多。這些整數比較也經常在單個處理器週期中完成。 – Yakk 2013-05-12 03:18:21

回答

25

這未必如此,但可能是最的時間情況。

考慮以下情況:

我想字符串「蘋果」的比較與「橘子」。如果我只想確定「蘋果」==「桔子」,我只需要比較每個字符串的第一個字符:'a'!='o'=>「apples」!=「oranges」。如果我對字符串進行散列並進行比較,那麼它會顯着變慢,因爲在比較所得到的整數之前,我必須解析這兩個字符串並將它們送入哈希算法。如果我需要做很多次這樣的比較,也許我會比較「桔子」和「猩猩」很多,那麼如果我把所有的字符串散列一次並且多次比較整數,它會工作得更快。這是散列圖所基於的原則。

但是,請注意,散列字符串對於直接等於比較非常有用,它不能確定字符串是否在文字上大於或小於彼此,因此通過散列方法排序字符串是不可能的。 (這就是爲什麼Java中的HashMap是無序的)。

+1

+1爲這個問題帶來有趣的方面 – SomeWittyUsername 2013-05-12 06:06:24

0

是的,但這與散列無關。

比較數字涉及比較位的簡單硬件指令。

比較字符串包括(a)遍歷兩個字符串,直到找到不同的字符(不像數字,它是固定大小)和(b)大量的Unicode魔術(不同長度的字符串實際上可以相等,且不同不同代碼塊中的字符的比較不同)。


散列通常用於將字符串轉換爲數組索引。

+0

我有一個預感 - 約翰尼= 12,約翰尼= 5。12 = 1100在二進制5 = 0101.比較數字(轉換爲二進制後)比。比較4個字符-john-(每個字符都有自己的二進制代碼),然後意識到它們是不一樣的。但是,如果名稱以不同的字母開頭,那麼哈希將不會有幫助。說得通 ?我不確定它是否正確。 – 2013-05-12 02:58:14

+0

由於可能的字符串組合的方式比平均字符串容量更大,因此您將有很多匹配相同數字的字符串,因此您必須檢查它們是否匹配,如果匹配,請執行真正的糾錯操作。此外,你打破了所有SLak提到的unicode問題。 – SJuan76 2013-05-12 03:07:49

+0

@SLaks我懷疑你的大部分數字是固定的大小。 :) Bignums需要迭代,比較而言,更爲奇特的「數字」(懶惰評估,符號計算,實數等)可能相當昂貴。但更嚴重的是,在什麼世界將一個字符串轉換爲數組索引? – Yakk 2013-05-12 03:15:12

1

比較原始數字肯定比比較字符串更快,因爲它只是一個計算機指令,而在Java中比較字符串是一種方法。但是Java中的散列用於不同的原因,Object.hashCode()用於散列表中以便在集合中進行快速搜索。

8

比較兩個數字的幅度比比較兩個字符串(表示相同的數字)更快。比較兩個數字僅僅需要比較各個位,並可能超快速使用任何的AND,XOR,2的補等

比較兩個字符串是非常緩慢和昂貴來完成。大多數算法需要遍歷整個字符串並匹配每個字符。

例如,假設我們要比較9和12(假)。對於數字比較,我們假設算法比較單個位。 9 = 1001 12 = 1100

這裏,最壞的情況下算法將比較4比特

現在,如果我們將「9」和「12」表示爲字符串,它們將作爲16位存儲在內存中(回憶:Java使用UTF-16表示內存中的字符串),並且必須傳遞給String比較算法。事實上,Java的實際字符串比較函數如下所示:

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; 
} 

正如你可以看到,有很多更要對周圍的字符串比較。

+0

我也喜歡你的答案。請告訴我這是什麼anotherString.count?我在API的任何地方都看不到.count。你的意思是String.length()? – 2013-05-17 07:51:34

1

一般情況下,大多數計算機都具有單指令比較整數,渴望等 ,並會採取最多幾個指令週期。通常通過效用函數/方法比較字符串(這個規則可能有一個奇怪的例外)。

在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方法做既此== anObjectn ==可anotherString .count,即使在開始比較字符之前,兩者基本上都是整數比較。這是要花費更長的時間比一個指令,一個整數比較需要


C字符串比較簡單/比Java快等價的,但它包含了某種循環和多條指令每次通過循環。

這將花費比一個指令,一個整數比較長,需要