void _buildTree(string[] keywords) { //build keyword tree and transition function _root = new InnerNode(null, ' '); var keywordCount = keywords.Length; for (int i = 0; i < keywordCount; ++i) { var p = keywords[i]; // add pattern to tree InnerNode nd = _root; foreach (var c in p) { InnerNode ndNew = null; foreach (InnerNode trans in nd._transitionsArr) { if (trans._char == c) { ndNew = trans; break; } } if (ndNew == null) { ndNew = new InnerNode(nd, c); nd.AddTransition(ndNew); } nd = ndNew; } nd.AddResult(p, i); } // Find failure functions var nodes = new List <InnerNode>(); // level 1 nodes - fail to root node foreach (InnerNode nd in _root._transitionsArr) { nd._failure = _root; foreach (InnerNode trans in nd._transitionsArr) { nodes.Add(trans); } } // other nodes - using BFS while (nodes.Count != 0) { var newNodes = new List <InnerNode>(); foreach (InnerNode nd in nodes) { InnerNode r = nd._parent._failure; char c = nd._char; while (r != null && !r.ContainsTransition(c)) { r = r._failure; } if (r == null) { nd._failure = _root; } else { nd._failure = r.GetTransition(c); foreach (var result in nd._failure._results) { nd.AddResult(result.Key, result.Value); } } // add child nodes to BFS list foreach (InnerNode child in nd._transitionsArr) { newNodes.Add(child); } } nodes = newNodes; } _root._failure = _root; }