trie.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. // Copyright 2007 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Datastructure: Trie.
  16. *
  17. *
  18. * This file provides the implementation of a trie data structure. A trie is a
  19. * data structure that stores key/value pairs in a prefix tree. See:
  20. * http://en.wikipedia.org/wiki/Trie
  21. */
  22. goog.provide('goog.structs.Trie');
  23. goog.require('goog.object');
  24. goog.require('goog.structs');
  25. /**
  26. * Class for a Trie datastructure. Trie data structures are made out of trees
  27. * of Trie classes.
  28. *
  29. * @param {goog.structs.Trie<VALUE>|Object<string, VALUE>=} opt_trie Optional
  30. * goog.structs.Trie or Object to initialize trie with.
  31. * @constructor
  32. * @template VALUE
  33. */
  34. goog.structs.Trie = function(opt_trie) {
  35. /**
  36. * This trie's value. For the base trie, this will be the value of the
  37. * empty key, if defined.
  38. * @private {VALUE}
  39. */
  40. this.value_ = undefined;
  41. /**
  42. * This trie's child nodes.
  43. * @private {!Object<!goog.structs.Trie<VALUE>>}
  44. */
  45. this.childNodes_ = {};
  46. if (opt_trie) {
  47. this.setAll(opt_trie);
  48. }
  49. };
  50. /**
  51. * Sets the given key/value pair in the trie. O(L), where L is the length
  52. * of the key.
  53. * @param {string} key The key.
  54. * @param {VALUE} value The value.
  55. */
  56. goog.structs.Trie.prototype.set = function(key, value) {
  57. this.setOrAdd_(key, value, false);
  58. };
  59. /**
  60. * Adds the given key/value pair in the trie. Throw an exception if the key
  61. * already exists in the trie. O(L), where L is the length of the key.
  62. * @param {string} key The key.
  63. * @param {VALUE} value The value.
  64. */
  65. goog.structs.Trie.prototype.add = function(key, value) {
  66. this.setOrAdd_(key, value, true);
  67. };
  68. /**
  69. * Helper function for set and add. Adds the given key/value pair to
  70. * the trie, or, if the key already exists, sets the value of the key. If
  71. * opt_add is true, then throws an exception if the key already has a value in
  72. * the trie. O(L), where L is the length of the key.
  73. * @param {string} key The key.
  74. * @param {VALUE} value The value.
  75. * @param {boolean=} opt_add Throw exception if key is already in the trie.
  76. * @private
  77. */
  78. goog.structs.Trie.prototype.setOrAdd_ = function(key, value, opt_add) {
  79. var node = this;
  80. for (var characterPosition = 0; characterPosition < key.length;
  81. characterPosition++) {
  82. var currentCharacter = key.charAt(characterPosition);
  83. if (!node.childNodes_[currentCharacter]) {
  84. node.childNodes_[currentCharacter] = new goog.structs.Trie();
  85. }
  86. node = node.childNodes_[currentCharacter];
  87. }
  88. if (opt_add && node.value_ !== undefined) {
  89. throw Error('The collection already contains the key "' + key + '"');
  90. } else {
  91. node.value_ = value;
  92. }
  93. };
  94. /**
  95. * Adds multiple key/value pairs from another goog.structs.Trie or Object.
  96. * O(N) where N is the number of nodes in the trie.
  97. * @param {!Object<string, VALUE>|!goog.structs.Trie<VALUE>} trie Object
  98. * containing the data to add.
  99. */
  100. goog.structs.Trie.prototype.setAll = function(trie) {
  101. var keys = goog.structs.getKeys(trie);
  102. var values = goog.structs.getValues(trie);
  103. for (var i = 0; i < keys.length; i++) {
  104. this.set(keys[i], values[i]);
  105. }
  106. };
  107. /**
  108. * Traverse along the given path, returns the child node at ending.
  109. * Returns undefined if node for the path doesn't exist.
  110. * @param {string} path The path to traverse.
  111. * @return {!goog.structs.Trie<VALUE>|undefined}
  112. * @private
  113. */
  114. goog.structs.Trie.prototype.getChildNode_ = function(path) {
  115. var node = this;
  116. for (var characterPosition = 0; characterPosition < path.length;
  117. characterPosition++) {
  118. var currentCharacter = path.charAt(characterPosition);
  119. node = node.childNodes_[currentCharacter];
  120. if (!node) {
  121. return undefined;
  122. }
  123. }
  124. return node;
  125. };
  126. /**
  127. * Retrieves a value from the trie given a key. O(L), where L is the length of
  128. * the key.
  129. * @param {string} key The key to retrieve from the trie.
  130. * @return {VALUE|undefined} The value of the key in the trie, or undefined if
  131. * the trie does not contain this key.
  132. */
  133. goog.structs.Trie.prototype.get = function(key) {
  134. var node = this.getChildNode_(key);
  135. return node ? node.value_ : undefined;
  136. };
  137. /**
  138. * Retrieves all values from the trie that correspond to prefixes of the given
  139. * input key. O(L), where L is the length of the key.
  140. *
  141. * @param {string} key The key to use for lookup. The given key as well as all
  142. * prefixes of the key are retrieved.
  143. * @param {?number=} opt_keyStartIndex Optional position in key to start lookup
  144. * from. Defaults to 0 if not specified.
  145. * @return {!Object<string, VALUE>} Map of end index of matching prefixes and
  146. * corresponding values. Empty if no match found.
  147. */
  148. goog.structs.Trie.prototype.getKeyAndPrefixes = function(
  149. key, opt_keyStartIndex) {
  150. var node = this;
  151. var matches = {};
  152. var characterPosition = opt_keyStartIndex || 0;
  153. if (node.value_ !== undefined) {
  154. matches[characterPosition] = node.value_;
  155. }
  156. for (; characterPosition < key.length; characterPosition++) {
  157. var currentCharacter = key.charAt(characterPosition);
  158. if (!(currentCharacter in node.childNodes_)) {
  159. break;
  160. }
  161. node = node.childNodes_[currentCharacter];
  162. if (node.value_ !== undefined) {
  163. matches[characterPosition] = node.value_;
  164. }
  165. }
  166. return matches;
  167. };
  168. /**
  169. * Gets the values of the trie. Not returned in any reliable order. O(N) where
  170. * N is the number of nodes in the trie. Calls getValuesInternal_.
  171. * @return {!Array<VALUE>} The values in the trie.
  172. */
  173. goog.structs.Trie.prototype.getValues = function() {
  174. var allValues = [];
  175. this.getValuesInternal_(allValues);
  176. return allValues;
  177. };
  178. /**
  179. * Gets the values of the trie. Not returned in any reliable order. O(N) where
  180. * N is the number of nodes in the trie. Builds the values as it goes.
  181. * @param {!Array<VALUE>} allValues Array to place values into.
  182. * @private
  183. */
  184. goog.structs.Trie.prototype.getValuesInternal_ = function(allValues) {
  185. if (this.value_ !== undefined) {
  186. allValues.push(this.value_);
  187. }
  188. for (var childNode in this.childNodes_) {
  189. this.childNodes_[childNode].getValuesInternal_(allValues);
  190. }
  191. };
  192. /**
  193. * Gets the keys of the trie. Not returned in any reliable order. O(N) where
  194. * N is the number of nodes in the trie (or prefix subtree).
  195. * @param {string=} opt_prefix Find only keys with this optional prefix.
  196. * @return {!Array<string>} The keys in the trie.
  197. */
  198. goog.structs.Trie.prototype.getKeys = function(opt_prefix) {
  199. var allKeys = [];
  200. if (opt_prefix) {
  201. // Traverse to the given prefix, then call getKeysInternal_ to dump the
  202. // keys below that point.
  203. var node = this;
  204. for (var characterPosition = 0; characterPosition < opt_prefix.length;
  205. characterPosition++) {
  206. var currentCharacter = opt_prefix.charAt(characterPosition);
  207. if (!node.childNodes_[currentCharacter]) {
  208. return [];
  209. }
  210. node = node.childNodes_[currentCharacter];
  211. }
  212. node.getKeysInternal_(opt_prefix, allKeys);
  213. } else {
  214. this.getKeysInternal_('', allKeys);
  215. }
  216. return allKeys;
  217. };
  218. /**
  219. * Private method to get keys from the trie. Builds the keys as it goes.
  220. * @param {string} keySoFar The partial key (prefix) traversed so far.
  221. * @param {!Array<string>} allKeys The partially built array of keys seen so
  222. * far.
  223. * @private
  224. */
  225. goog.structs.Trie.prototype.getKeysInternal_ = function(keySoFar, allKeys) {
  226. if (this.value_ !== undefined) {
  227. allKeys.push(keySoFar);
  228. }
  229. for (var childNode in this.childNodes_) {
  230. this.childNodes_[childNode].getKeysInternal_(keySoFar + childNode, allKeys);
  231. }
  232. };
  233. /**
  234. * Checks to see if a certain key is in the trie. O(L), where L is the length
  235. * of the key.
  236. * @param {string} key A key that may be in the trie.
  237. * @return {boolean} Whether the trie contains key.
  238. */
  239. goog.structs.Trie.prototype.containsKey = function(key) {
  240. return this.get(key) !== undefined;
  241. };
  242. /**
  243. * Checks to see if a certain prefix is in the trie. O(L), where L is the length
  244. * of the prefix.
  245. * @param {string} prefix A prefix that may be in the trie.
  246. * @return {boolean} Whether any key of the trie has the prefix.
  247. */
  248. goog.structs.Trie.prototype.containsPrefix = function(prefix) {
  249. // Empty string is any key's prefix.
  250. if (prefix.length == 0) {
  251. return !this.isEmpty();
  252. }
  253. return !!this.getChildNode_(prefix);
  254. };
  255. /**
  256. * Checks to see if a certain value is in the trie. Worst case is O(N) where
  257. * N is the number of nodes in the trie.
  258. * @param {VALUE} value A value that may be in the trie.
  259. * @return {boolean} Whether the trie contains the value.
  260. */
  261. goog.structs.Trie.prototype.containsValue = function(value) {
  262. if (this.value_ === value) {
  263. return true;
  264. }
  265. for (var childNode in this.childNodes_) {
  266. if (this.childNodes_[childNode].containsValue(value)) {
  267. return true;
  268. }
  269. }
  270. return false;
  271. };
  272. /**
  273. * Completely empties a trie of all keys and values. ~O(1)
  274. */
  275. goog.structs.Trie.prototype.clear = function() {
  276. this.childNodes_ = {};
  277. this.value_ = undefined;
  278. };
  279. /**
  280. * Removes a key from the trie or throws an exception if the key is not in the
  281. * trie. O(L), where L is the length of the key.
  282. * @param {string} key A key that should be removed from the trie.
  283. * @return {VALUE} The value whose key was removed.
  284. */
  285. goog.structs.Trie.prototype.remove = function(key) {
  286. var node = this;
  287. var parents = [];
  288. for (var characterPosition = 0; characterPosition < key.length;
  289. characterPosition++) {
  290. var currentCharacter = key.charAt(characterPosition);
  291. if (!node.childNodes_[currentCharacter]) {
  292. throw Error('The collection does not have the key "' + key + '"');
  293. }
  294. // Archive the current parent and child name (key in childNodes_) so that
  295. // we may remove the following node and its parents if they are empty.
  296. parents.push([node, currentCharacter]);
  297. node = node.childNodes_[currentCharacter];
  298. }
  299. var oldValue = node.value_;
  300. delete node.value_;
  301. while (parents.length > 0) {
  302. var currentParentAndCharacter = parents.pop();
  303. var currentParent = currentParentAndCharacter[0];
  304. var currentCharacter = currentParentAndCharacter[1];
  305. if (currentParent.childNodes_[currentCharacter].isEmpty()) {
  306. // If the child is empty, then remove it.
  307. delete currentParent.childNodes_[currentCharacter];
  308. } else {
  309. // No point of traversing back any further, since we can't remove this
  310. // path.
  311. break;
  312. }
  313. }
  314. return oldValue;
  315. };
  316. /**
  317. * Clones a trie and returns a new trie. O(N), where N is the number of nodes
  318. * in the trie.
  319. * @return {!goog.structs.Trie<VALUE>} A new goog.structs.Trie with the same
  320. * key value pairs.
  321. */
  322. goog.structs.Trie.prototype.clone = function() {
  323. return new goog.structs.Trie(this);
  324. };
  325. /**
  326. * Returns the number of key value pairs in the trie. O(N), where N is the
  327. * number of nodes in the trie.
  328. * TODO: This could be optimized by storing a weight (count below) in every
  329. * node.
  330. * @return {number} The number of pairs.
  331. */
  332. goog.structs.Trie.prototype.getCount = function() {
  333. return goog.structs.getCount(this.getValues());
  334. };
  335. /**
  336. * Returns true if this trie contains no elements. ~O(1).
  337. * @return {boolean} True iff this trie contains no elements.
  338. */
  339. goog.structs.Trie.prototype.isEmpty = function() {
  340. return this.value_ === undefined && goog.object.isEmpty(this.childNodes_);
  341. };