2011-02-05 8 views
28

बॉयर-मूर शायद सबसे तेज़ गैर-अनुक्रमित टेक्स्ट-सर्च एल्गोरिदम ज्ञात है। इसलिए मैं इसे Black Belt Coder वेबसाइट के लिए सी # में कार्यान्वित कर रहा हूं।सी # में बॉयर-मूर प्रैक्टिकल?

मैंने यह काम किया था और यह String.IndexOf() की तुलना में अनुमानित प्रदर्शन सुधारों को दिखाता है। हालांकि, जब मैंने StringComparison.OrdinalIndexOf पर तर्क जोड़ा, तो उसने मेरे बॉयर-मूर कार्यान्वयन को बेहतर प्रदर्शन करना शुरू कर दिया। कभी-कभी, काफी मात्रा में।

मुझे आश्चर्य है कि कोई मुझे यह जानने में मदद कर सकता है कि क्यों। मैं समझता हूं कि क्यों StringComparision.Ordinal चीजों को गति दे सकता है, लेकिन यह बॉयर-मूर से तेज कैसे हो सकता है? क्या यह .NET प्लेटफार्म के ऊपरी हिस्से की वजह से है, शायद इसलिए कि सरणी इंडेक्स को यह सुनिश्चित करने के लिए मान्य किया जाना चाहिए कि वे सीमा में हैं, या कुछ और पूरी तरह से। क्या कुछ एल्गोरिदम सी # .NET में व्यावहारिक नहीं हैं?

नीचे कुंजी कोड है।

// Base for search classes 
abstract class SearchBase 
{ 
    public const int InvalidIndex = -1; 
    protected string _pattern; 
    public SearchBase(string pattern) { _pattern = pattern; } 
    public abstract int Search(string text, int startIndex); 
    public int Search(string text) { return Search(text, 0); } 
} 

/// <summary> 
/// A simplified Boyer-Moore implementation. 
/// 
/// Note: Uses a single skip array, which uses more memory than needed and 
/// may not be large enough. Will be replaced with multi-stage table. 
/// </summary> 
class BoyerMoore2 : SearchBase 
{ 
    private byte[] _skipArray; 

    public BoyerMoore2(string pattern) 
     : base(pattern) 
    { 
     // TODO: To be replaced with multi-stage table 
     _skipArray = new byte[0x10000]; 

     for (int i = 0; i < _skipArray.Length; i++) 
      _skipArray[i] = (byte)_pattern.Length; 
     for (int i = 0; i < _pattern.Length - 1; i++) 
      _skipArray[_pattern[i]] = (byte)(_pattern.Length - i - 1); 
    } 

    public override int Search(string text, int startIndex) 
    { 
     int i = startIndex; 

     // Loop while there's still room for search term 
     while (i <= (text.Length - _pattern.Length)) 
     { 
      // Look if we have a match at this position 
      int j = _pattern.Length - 1; 
      while (j >= 0 && _pattern[j] == text[i + j]) 
       j--; 

      if (j < 0) 
      { 
       // Match found 
       return i; 
      } 

      // Advance to next comparision 
      i += Math.Max(_skipArray[text[i + j]] - _pattern.Length + 1 + j, 1); 
     } 
     // No match found 
     return InvalidIndex; 
    } 
} 

संपादित करें: मैं http://www.blackbeltcoder.com/Articles/algorithms/fast-text-search-with-boyer-moore बिल्कुल अपने परीक्षण कोड और इस मामले पर निष्कर्ष पोस्ट किया है।

+4

जोनाथन, "सी # .NET" जैसी कोई चीज़ नहीं है। –

+0

क्या आप इस संभावना को पूरी तरह से बाहर कर रहे हैं कि बॉयर-मूर आंतरिक रूप से .NET में नियोजित है? बस उत्सुक। –

+0

http://stackoverflow.com/questions/2584169/what-algorithm-net-use-for-searching-a-pattern-in-a-string और विशेष रूप से स्वीकृत उत्तर के तहत टिप्पणियां देखें। –

उत्तर

19

मेरे अपने परीक्षणों और टिप्पणियों के आधार पर, मैंने निष्कर्ष निकाला है कि String.IndexOf()StringComparision.Ordinal के साथ इतना अच्छा प्रदर्शन करता है क्योंकि विधि अप्रबंधित कोड में कॉल करती है जो संभावित रूप से हाथ-अनुकूलित असेंबली भाषा को नियोजित करती है।

मैंने कई अलग-अलग परीक्षण चलाए हैं और String.IndexOf() प्रबंधित सी # कोड का उपयोग करके मैं कुछ भी लागू कर सकता हूं।

यदि कोई दिलचस्पी लेता है, तो मैंने इसके बारे में जो कुछ भी खोजा है, मैंने लिखा है और http://www.blackbeltcoder.com/Articles/algorithms/fast-text-search-with-boyer-moore पर सी # में बॉयर-मूर एल्गोरिदम के कई बदलाव पोस्ट किए हैं।

+0

जो लोग इसे पा सकते हैं, उनके लिए उपयोगी है, स्ट्रिंग। कंटेनर() कॉल स्ट्रिंग.इंडेक्सऑफ (मान, स्ट्रिंग कॉम्पर्सन.ऑर्डिनल)> = 0। इसलिए स्ट्रिंग खोज – ValidfroM

+0

के लिए String.Conatinst() का उपयोग करना है यह निष्कर्ष डेटा निर्भर है। बॉयर मूर उपयुक्त डेटा पर मनमाने ढंग से तेज़ हो सकता है। – usr

+0

@usr: ठीक है, अगर आपके पास सबूत हैं कि यह किसी मामले में तेज़ है, तो कृपया उस सबूत को प्रस्तुत करने में संकोच न करें। मुझे बॉयर-मूर की पूरी तरह से समझ है, और पूरी तरह से समझता है कि यह कुछ डेटा के लिए तेज़ कैसे है, लेकिन मैंने विभिन्न प्रकार के डेटा का परीक्षण किया और 'स्ट्रिंग.इंडेक्सऑफ()' तेजी से काफी तेजी से लग रहा था। –

4

मेरी शर्त यह है कि ध्वज यह सेट करता है कि फ्लैग स्ट्रिंग.इंडेक्स को बॉयर-मूर का उपयोग करने की अनुमति देता है। और इसका कार्यान्वयन आपके से बेहतर है।

उस ध्वज के बिना इसे यूनिकोड के आसपास संभावित मुद्दों की वजह से बॉयर-मूर (और शायद नहीं) का उपयोग करके सावधान रहना होगा। विशेष रूप से यूनिकोड की संभावना संक्रमण तालिकाओं का कारण बनती है जो बॉयर-मूर उड़ने के लिए उपयोग करता है।

+0

ठीक है, यह एक साफ चाल होगी क्योंकि मैं कुछ सुंदर मानक कार्यान्वयन का उपयोग कर रहा हूं। (वे मेरा नहीं हैं, बीटीडब्लू।) हालांकि, अगर यह अप्रबंधित कोड में चलता है, तो यह कुछ प्रदर्शन लाभ प्रदान कर सकता है। –

+2

यदि बीसीएल बॉयर-मूर खोज का उपयोग कर रहा है, तो यह पता लगाने योग्य होना चाहिए; एक लंबी स्ट्रिंग ("abcdefghijklmnopqrstuvwxyz") की खोज करना एक छोटी स्ट्रिंग ("ए") की खोज करने से मापने योग्य रूप से तेज़ होना चाहिए। – Gabe

+0

@Gabe: अच्छा बिंदु, लेकिन ऐसा प्रतीत नहीं होता है। यह बस कोई फर्क नहीं पड़ता कि क्या कोई फर्क नहीं पड़ता। दूसरी ओर, मेरे बॉयर-मूर दिनचर्या निश्चित रूप से खोज पैटर्न की लंबाई से प्रभावित होती हैं। –

संबंधित मुद्दे