采用DAWG方式在大批量字符串中查询字符串

最近在一个项目中需要针对上百万条(大约在800W条)的字符串进行相关的处理。该字符串是以文本的形式存放在本地硬盘,并且更新频率为20分钟一次。

具体需求:

1、判断某一个字符串是否存在这800W条字符串中,时间要求在5ms以内

2、根据字符串前缀,返回包含此前缀的10-100条字符串。时间要求在5ms以内

3、占用内存要小

本人接到此需求第一反应用List,或者二叉树啥的。结果效率慢得死,

后经过大量资料查阅,发现采用DAWG(Directed Acyclic Word Graph)和Trie可以很快速的查找到相应的字符串。

主要思路:将每个字符串的字符进行创建相应的Node,如果有相同的字符则放置在同一个节点中。

例如有6个字符串:Top, Tops, Tap, Tapc, Topa and Taps。根据DAWG和Trie的原理将创建成如下一个Tree

采用DAWG方式在大批量字符串中查询字符串

在添加字符串的时候,根据字符串的字符创建树形结构,每个节点代表一个字符。如果是相同字符时,则存储在同一个节点中。这样可少占用内存。

在进行判断字符串是否存在时,只需要依次判断字符串的节点是否存在。

首先创建一个字符节点类LetterNode. 该类主要用于存储相关字符节点的信息:子节点,父节点等等。

View Code
     ///   <summary>
    
///  The Dawg's letter node
    
///   </summary>
     internal   sealed   class  LetterNode
    {
        
private   const   int  InitialSpreadCapacity  =   4 ;

        
private  Dictionary < char , LetterNode >  _childNodes;

        
///   <summary>
        
///  Initializes a new instance of the  <see cref="LetterNode"/>  class.
        
///   </summary>
         public  LetterNode()
        {
        }

        
///   <summary>
        
///  Initializes a new instance of the  <see cref="LetterNode"/>  class.
        
///   </summary>
        
///   <param name="letter"> The letter. </param>
         public  LetterNode( char  letter)
            : 
this ()
        {
            Letter 
=  letter;
        }

        
///   <summary>
        
///  The node's child nodes
        
///   </summary>
         public  Dictionary < char , LetterNode >  ChildNodes
        {
            
get
            {
                
if  ( this ._childNodes  ==   null )
                {
                    
this ._childNodes  =   new  Dictionary < char , LetterNode > (InitialSpreadCapacity);
                }
                
return   this ._childNodes;
            }
        }


        
///   <summary>
        
///  Describe the node is end of the word.
        
///   </summary>
         public   bool  IsEndOfWord
        {
            
get ;
            
set ;
        }

        
///   <summary>
        
///  Gets or sets the letter.
        
///   </summary>
        
///   <value> The letter. </value>
         public   char  Letter
        {
            
get ;
            
set ;
        }

        
///   <summary>
        
///  Gets or sets the parent of this node.
        
///   </summary>
        
///   <value> The parent. </value>
         public  LetterNode Parent
        {
            
get ;
            
set ;
        }

        
///   <summary>
        
///  Gets the word defined at this element.
        
///   </summary>
        
///   <value> The word ending here (if this is a word, or the empty string. </value>
         public   string  Word
        {
            
get
            {
                
if  (IsEndOfWord)
                {
                    StringBuilder sb 
=   new  StringBuilder( 20 );
                    sb.Append(Letter);
                    var node 
=  Parent;
                    
while  (node  !=   null )
                    {
                        sb.Insert(
0 , node.Letter);
                        node 
=  node.Parent;
                    }
                    
return  sb.ToString();
                }
                
else
                {
                    
return   string .Empty;
                }
            }
        }

    }

接下来实现Dawg针对字符串创建树形节点。思路是参照上图。

         ///   <summary>
        
///  Adds the specified item.
        
///   </summary>
        
///   <param name="item"> The item. </param>
         public   void  Add( string  item)
        {
            
if  ( string .IsNullOrEmpty(item))
            {
                
return ;
            }

            item 
=  item.ToLowerInvariant();

            LetterNode node 
=   null , parentNode  =   null ;

            
if  ( ! this ._rootNodes.TryGetValue(item[ 0 ],  out  node))
            {
                node 
=   new  LetterNode(item[ 0 ]);
                
this ._rootNodes[item[ 0 ]]  =  node;
            }

            
for  ( int  i  =   1 ; i  <  item.Length;  ++ i)
            {
                parentNode 
=  node;
                
if  ( ! node.ChildNodes.TryGetValue(item[i],  out  node))
                {
                    node 
=   new  LetterNode(item[i]);
                    node.Parent 
=  parentNode;
                    parentNode.ChildNodes[item[i]] 
=  node;
                }
            }

            
if  ( ! node.IsEndOfWord)
            {
                node.IsEndOfWord 
=   true ;
                
this ._count ++ ;
            }
        }

 判断字符串是否存在:

         private  LetterNode SearchPrefixLetterNode( string  prefix)
        {
            prefix 
=  prefix.ToLowerInvariant();

            Dictionary
< char , LetterNode >  nodes  =   this ._rootNodes;

            LetterNode node 
=   null ;

            
for  ( int  i  =   0 ; i  <  prefix.Length;  ++ i)
            {
                
if  (nodes.TryGetValue(prefix[i],  out  node))
                {
                    nodes 
=  node.ChildNodes;
                }
                
else
                {
                    
return   null ;
                }
            }
            
return  node;
        }
         public   bool  Contains( string  item)
        {
            var node 
=   this .SearchPrefixLetterNode(item);
            
return  node  !=   null   &&  node.IsEndOfWord;
        }

代码可从此处下载:http://files.cnblogs.com/foolishfox/Dawg.zip

你可能感兴趣的:(字符串)