public override TrieNodeBase AddChild(char c, ref int node_count) { if (nodes == null) { m_base = c; nodes = new TrieNodeBase[1]; } else if (c >= m_base + nodes.Length) { Array.Resize(ref nodes, c - m_base + 1); } else if (c < m_base) { Char c_new = (Char)(m_base - c); TrieNodeBase[] tmp = new TrieNodeBase[nodes.Length + c_new]; nodes.CopyTo(tmp, c_new); m_base = c; nodes = tmp; } TrieNodeBase node = nodes[c - m_base]; if (node == null) { node = new TrieNode(); node_count++; nodes[c - m_base] = node; } return(node); }
/// <summary> /// Debug only; this is hideously inefficient /// </summary> public string GetKey(TrieNodeBase seek) { var sofar = string.Empty; GetKeyHelper fn = null; fn = cur => { sofar += " "; // placeholder foreach (var kvp in cur.CharNodePairs()) { //Util.SetStringChar(ref sofar, sofar.Length - 1, kvp.Key); if (kvp.Value == seek) { return(true); } if (kvp.Value.Nodes != null && fn(kvp.Value)) { return(true); } } sofar = sofar.Substring(0, sofar.Length - 1); return(false); }; if (fn(Root)) { return(sofar); } return(null); }
public override void ReplaceChild(Char c, TrieNodeBase n) { if (nodes == null || c >= m_base + nodes.Length || c < m_base) { throw new Exception(); } nodes[c - m_base] = n; }
public void OptimizeSparseNodes() { if (Root.ShouldOptimize) { Root = new SparseTrieNode(Root.CharNodePairs()); c_sparse_nodes++; } Root.OptimizeChildNodes(); }
public TValue ContainsKey(String s_in) { TrieNodeBase node = FindNode(s_in); if (node == null || !node.HasValue()) { return(default(TValue)); } return(node.Value); }
public IEnumerable <TrieNodeBase> SubsumedNodes(String s) { TrieNodeBase node = FindNode(s); if (node == null) { return(Enumerable.Empty <TrieNodeBase>()); } return(node.SubsumedNodes()); }
public TrieNodeBase Add(String s, TValue v) { TrieNodeBase node = _root; foreach (Char c in s) { node = node.AddChild(c, ref c_nodes); } node.Value = v; return(node); }
public TrieNodeBase FindNode(String s_in) { TrieNodeBase node = _root; foreach (Char c in s_in) { if ((node = node[c]) == null) { return(null); } } return(node); }
public bool Contains(String s) { TrieNodeBase node = _root; foreach (Char c in s) { node = node[c]; if (node == null) { return(false); } } return(node.HasValue); }
public unsafe TValue Find(Char *p_tag, int cb_ctag) { TrieNodeBase node = _root; Char * p_end = p_tag + cb_ctag; while (p_tag < p_end) { if ((node = node[*p_tag]) == null) { return(default(TValue)); } p_tag++; } return(node.Value); }
public IEnumerable <TValue> FindAll(String s_in) { TrieNodeBase node = _root; foreach (Char c in s_in) { if ((node = node[c]) == null) { break; } if (node.Value != null) { yield return(node.Value); } } }
/// <summary> /// Note: doesn't de-optimize optimized nodes if re-run later /// </summary> public void OptimizeChildNodes() { if (Nodes != null) { foreach (var q in CharNodePairs()) { TrieNodeBase n_old = q.Value; if (n_old.ShouldOptimize) { TrieNodeBase n_new = new SparseTrieNode(n_old.CharNodePairs()); n_new.m_value = n_old.m_value; Trie <TValue> .c_sparse_nodes++; ReplaceChild(q.Key, n_new); } n_old.OptimizeChildNodes(); } } }
/// <summary> /// If continuation from the terminal node is possible with a different input string, then that node is not /// returned as a 'last' node for the given input. In other words, 'last' nodes must be leaf nodes, where /// continuation possibility is truly unknown. The presense of a nodes array that we couldn't match to /// means the search fails; it is not the design of the 'OrLast' feature to provide 'closest' or 'best' /// matching but rather to enable truncated tails still in the context of exact prefix matching. /// </summary> public TrieNodeBase FindNodeOrLast(String s_in, out bool f_exact) { TrieNodeBase node = _root; foreach (Char c in s_in) { if (node.IsLeaf) { f_exact = false; return(node); } if ((node = node[c]) == null) { f_exact = false; return(null); } } f_exact = true; return(node); }
// even though I found some articles that attest that using a foreach enumerator with arrays (and Lists) // returns a value type, thus avoiding spurious garbage, I had already changed the code to not use enumerator. public unsafe TValue Find(String s_in) { TrieNodeBase node = _root; fixed(Char *pin_s = s_in) { Char *p = pin_s; Char *p_end = p + s_in.Length; while (p < p_end) { if ((node = node[*p]) == null) { return(default(TValue)); } p++; } return(node.Value); } }
/// <summary> /// note: only returns nodes with non-null values /// </summary> public void EnumerateLeafPaths(Action <String, IEnumerable <TrieNodeBase> > callback) { Stack <TrieNodeBase> stk = new Stack <TrieNodeBase>(); Char[] rgch = new Char[100]; Action <TrieNodeBase> fn = null; fn = (TrieNodeBase cur) => { if (stk.Count >= rgch.Length) { Char[] tmp = new Char[rgch.Length * 2]; Buffer.BlockCopy(rgch, 0, tmp, 0, rgch.Length * sizeof(Char)); rgch = tmp; } foreach (var kvp in cur.CharNodePairs()) { rgch[stk.Count] = kvp.Key; TrieNodeBase n = kvp.Value; stk.Push(n); if (n.Nodes != null) { fn(n); } else { if (n.Value == null) // leaf nodes should always have a value { throw new Exception(); } callback(new String(rgch, 0, stk.Count), stk); } stk.Pop(); } }; fn(_root); }
/// <summary> /// note: only returns nodes with non-null values /// </summary> public void DepthFirstTraverse(Action <String, TrieNodeBase> callback) { Char[] rgch = new Char[100]; int depth = 0; Action <TrieNodeBase> fn = null; fn = (TrieNodeBase cur) => { if (depth >= rgch.Length) { Char[] tmp = new Char[rgch.Length * 2]; Buffer.BlockCopy(rgch, 0, tmp, 0, rgch.Length * sizeof(Char)); rgch = tmp; } foreach (var kvp in cur.CharNodePairs()) { rgch[depth] = kvp.Key; TrieNodeBase n = kvp.Value; if (n.Nodes != null) { depth++; fn(n); depth--; } else if (n.Value == null) // leaf nodes should always have a value { throw new Exception(); } if (n.Value != null) { callback(new String(rgch, 0, depth + 1), n); } } }; fn(_root); }
public IEnumerable <TValue> AllSubstringValues(String s) { int i_cur = 0; while (i_cur < s.Length) { TrieNodeBase node = _root; int i = i_cur; while (i < s.Length) { node = node[s[i]]; if (node == null) { break; } if (node.Value != null) { yield return(node.Value); } i++; } i_cur++; } }
public abstract void ReplaceChild(Char c, TrieNodeBase n);
public override void ReplaceChild(Char c, TrieNodeBase n) { d[c] = n; }