2012-09-04 108 views
12

我有一個名爲stb_Swap_Tabu一個StringBuilder用來存放課程的名稱, 我使用下面的方法找到一門課程:最快的搜索方法的StringBuilder

stb_Swap_Tabu.ToString.Contains("CourseName") 
在我的情況

,性能是最重要的問題。 有沒有更快的方法?

+1

如果你需要使用'StringBuilder',那麼你可能需要每次你想要調用'ToString'搜索,這在性能方面不是一個好主意。 'StringBuilder'用於*構建字符串*;大概如果你正在建造琴絃,那麼你已經有了組成部分;你爲什麼不直接在這些組成部分內進行搜索? – LukeH

+4

'StringBuilder'可能是最不適合存儲可搜索名稱列表的數據類型。爲什麼不用'List '代替,並使用'List'的'Contains'方法? – Rotem

+9

你有一個這個字符串實際是什麼的例子嗎?你說它存儲「課程名稱」 - 「課程」實際上是否意味着「課程」,「名稱」建議不止一個名稱 - 所以推測這是一個分隔字符串。在這種情況下,將其切換到*個人*名稱的'List '或'HashSet '將對大數字的字符串產生很大的意義 –

回答

21

StringBuilder並非真正用於所有字符串目的。如果你真的需要搜索一個,你必須編寫你自己的方法。

有幾種適用於不同情況的字符串搜索算法。

以下是Knuth-Morris-Pratt算法的一個簡單實現,它只關心序數匹配(沒有案例摺疊,沒有文化相關的排序規則,只是代碼點匹配的簡單代碼點)。它有一些初始的Θ(m)開銷,其中m是所尋找單詞的長度,然後在Θ(n)中找到,其中n是尋找單詞的距離,或者是整個字符串生成器的長度(如果它不存在)。這比簡單的char-by-char比較要好得多(其中O()符號描述了上限,Θ()描述了上限和下限)。

所有這一切說,它聽起來像創建一個列表可能是一個更好的方法來完成任務。

public static class StringBuilderSearching 
{ 
    public static bool Contains(this StringBuilder haystack, string needle) 
    { 
    return haystack.IndexOf(needle) != -1; 
    } 
    public static int IndexOf(this StringBuilder haystack, string needle) 
    { 
    if(haystack == null || needle == null) 
     throw new ArgumentNullException(); 
    if(needle.Length == 0) 
     return 0;//empty strings are everywhere! 
    if(needle.Length == 1)//can't beat just spinning through for it 
    { 
     char c = needle[0]; 
     for(int idx = 0; idx != haystack.Length; ++idx) 
     if(haystack[idx] == c) 
      return idx; 
     return -1; 
    } 
    int m = 0; 
    int i = 0; 
    int[] T = KMPTable(needle); 
    while(m + i < haystack.Length) 
    { 
     if(needle[i] == haystack[m + i]) 
     { 
     if(i == needle.Length - 1) 
      return m == needle.Length ? -1 : m;//match -1 = failure to find conventional in .NET 
     ++i; 
     } 
     else 
     { 
     m = m + i - T[i]; 
     i = T[i] > -1 ? T[i] : 0; 
     } 
    } 
    return -1; 
    }  
    private static int[] KMPTable(string sought) 
    { 
    int[] table = new int[sought.Length]; 
    int pos = 2; 
    int cnd = 0; 
    table[0] = -1; 
    table[1] = 0; 
    while(pos < table.Length) 
     if(sought[pos - 1] == sought[cnd]) 
     table[pos++] = ++cnd; 
     else if(cnd > 0) 
     cnd = table[cnd]; 
     else 
     table[pos++] = 0; 
    return table; 
    } 
} 
+1

就像@JonHanna所說的,我有一個很好的理由擁有一個構建器,這就是爲什麼我的問題標題是:** StringBuilder中最快的搜索方法* *。 由於我的測試,經過一些修改後@JonHanna提供的答案比使用Conatins好28%。我會盡量讓抽象的代碼在這裏分享。 – Alaa

+7

StringBuilder有一個'Replace'函數,它必須不可避免地搜索字符串,甚至需要開始和結束索引,但不提供'indexOf'函數。爲什麼我們要重做已經完成的工作? – Slight

+0

該代碼對於我來說乾草堆「abcde」和針「cd」失敗,它返回false。 –

0

我知道這是一個老問題,但在當時我是想,我認爲我需要尋找一個StringBuilder創建我自己的項目的解決方案我的搜索結果出來了,但後來我意識到我可能只是搜索我用來初始化字符串生成器的值。所以我的情況可能和你的不一樣,但我儘管我會分享:

Private Function valueFormatter(ByVal value As String) As String 
     ' This will correct any formatting to make the value valid for a CSV format 
     ' 
     ' 1) Any value that as a , in it then it must be wrapped in a " i.e. Hello,World -> "Hello,World" 
     ' 2) In order to escape a " in the value add a " i.e. Hello"World -> Hello""World 
     ' 3) if the value has a " in it then it must also be wrapped in a " i.e. "Hello World" -> ""Hello World"" -> """Hello World""" 
     ' 
     ' VB NOTATAION 
     ' " -> """" 
     ' "" -> """""" 

     If value.Contains(",") Or value.Contains("""") Then 
      Dim sb As New StringBuilder(value) 
      If value.Contains("""") Then sb.Replace("""", """""") 
      sb.Insert(0, """").Append("""") 
      Return sb.ToString 
     Else 
      Return value 
     End If 
    End Function