StrTrieDictionary.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. using System.Collections.Generic;
  2. namespace GFGGame
  3. {
  4. //支持String模糊查询的字典
  5. public class StrTrieDictionary<TValue>
  6. {
  7. private readonly Dictionary<string, TValue> dictionary;
  8. private readonly Trie trie;
  9. public StrTrieDictionary()
  10. {
  11. dictionary = new Dictionary<string, TValue>();
  12. trie = new Trie();
  13. }
  14. public void Add(string key, TValue value)
  15. {
  16. dictionary.Add(key, value);
  17. trie.Insert(key);
  18. }
  19. public List<string> SearchKeys(string pattern, int n)
  20. {
  21. return trie.Search(pattern, n);
  22. }
  23. public List<TValue> SearchByKeys(string pattern, int n)
  24. {
  25. var keys = trie.Search(pattern, n);
  26. var rs = new List<TValue>();
  27. foreach (var key in keys)
  28. {
  29. dictionary.TryGetValue(key, out var value);
  30. if (value != null) rs.Add(value);
  31. }
  32. return rs;
  33. }
  34. public TValue this[string key]
  35. {
  36. get => dictionary[key];
  37. set => Add(key, value);
  38. }
  39. public bool ContainsKey(string key)
  40. {
  41. return dictionary.ContainsKey(key);
  42. }
  43. public bool Remove(string key)
  44. {
  45. if (!dictionary.Remove(key)) return false;
  46. trie.Remove(key);
  47. return true;
  48. }
  49. }
  50. internal class TrieNode
  51. {
  52. public char Key { get; set; }
  53. public bool IsEndOfWord { get; set; }
  54. public Dictionary<char, TrieNode> Children { get; set; }
  55. public TrieNode(char key)
  56. {
  57. Key = key;
  58. IsEndOfWord = false;
  59. Children = new Dictionary<char, TrieNode>();
  60. }
  61. }
  62. internal class Trie
  63. {
  64. private readonly TrieNode root;
  65. public Trie()
  66. {
  67. root = new TrieNode('\0');
  68. }
  69. public void Insert(string word)
  70. {
  71. var node = root;
  72. foreach (var c in word)
  73. {
  74. if (!node.Children.ContainsKey(c))
  75. {
  76. node.Children[c] = new TrieNode(c);
  77. }
  78. node = node.Children[c];
  79. }
  80. node.IsEndOfWord = true;
  81. }
  82. public List<string> Search(string pattern, int n)
  83. {
  84. var result = new List<string>();
  85. var node = root;
  86. foreach (var c in pattern)
  87. {
  88. if (!node.Children.ContainsKey(c))
  89. {
  90. return result;
  91. }
  92. node = node.Children[c];
  93. }
  94. SearchHelper(node, pattern, result, n);
  95. return result;
  96. }
  97. private static void SearchHelper(TrieNode node, string prefix, ICollection<string> result, int n)
  98. {
  99. if (node.IsEndOfWord)
  100. {
  101. result.Add(prefix);
  102. }
  103. if (result.Count >= n)
  104. {
  105. return;
  106. }
  107. foreach (var child in node.Children.Values)
  108. {
  109. SearchHelper(child, prefix + child.Key, result, n);
  110. if (result.Count >= n)
  111. {
  112. return;
  113. }
  114. }
  115. }
  116. public bool Remove(string word)
  117. {
  118. var node = root;
  119. var stack = new Stack<TrieNode>();
  120. foreach (var c in word)
  121. {
  122. if (!node.Children.ContainsKey(c))
  123. {
  124. return false;
  125. }
  126. stack.Push(node);
  127. node = node.Children[c];
  128. }
  129. if (!node.IsEndOfWord)
  130. {
  131. return false;
  132. }
  133. node.IsEndOfWord = false;
  134. if (node.Children.Count != 0) return true;
  135. while (stack.Count > 0 && node.Children.Count == 0 && !node.IsEndOfWord)
  136. {
  137. var parent = stack.Pop();
  138. parent.Children.Remove(node.Key);
  139. node = parent;
  140. }
  141. return true;
  142. }
  143. }
  144. }