Show:
  1. /**
  2. * The Search Component
  3. *
  4. * @module aui-search
  5. * @submodule aui-search-ternary-search-tree
  6. */
  7. var Lang = A.Lang;
  8. /**
  9. * A base class for TernarySearchTree.
  10. *
  11. * @class A.TernarySearchTree
  12. * @extends Base
  13. * @param {Object} config Object literal specifying widget configuration
  14. * properties.
  15. * @constructor
  16. */
  17. var TernarySearchTree = A.Component.create({
  18. /**
  19. * Static property provides a string to identify the class.
  20. *
  21. * @property NAME
  22. * @type String
  23. * @static
  24. */
  25. NAME: 'TernarySearchTree',
  26. /**
  27. * Static property provides a string to identify the namespace.
  28. *
  29. * @property NS
  30. * @type String
  31. * @static
  32. */
  33. NS: 'ternarysearchtree',
  34. /**
  35. * Static property used to define which component it extends.
  36. *
  37. * @property EXTENDS
  38. * @type Object
  39. * @static
  40. */
  41. EXTENDS: A.Base,
  42. prototype: {
  43. /**
  44. * Adds a word in the tree.
  45. *
  46. * @method add
  47. * @param word
  48. */
  49. add: function(word) {
  50. var instance = this;
  51. var root = instance._root;
  52. var node = instance._insert(root, word, 0);
  53. if (!Lang.isValue(root)) {
  54. instance._root = node;
  55. }
  56. },
  57. /**
  58. * Checks if the argument is part of the tree.
  59. *
  60. * @method contains
  61. * @param word
  62. * @return {Boolean}
  63. */
  64. contains: function(word) {
  65. var instance = this;
  66. var node = instance._search(instance._root, word, 0);
  67. return !!(Lang.isValue(node) && node.isEndOfWord());
  68. },
  69. /**
  70. * Set tree's root to `null`.
  71. *
  72. * @method empty
  73. */
  74. empty: function() {
  75. var instance = this;
  76. instance._root = null;
  77. },
  78. /**
  79. * Checks if a pattern match.
  80. *
  81. * @method patternMatch
  82. * @param pattern
  83. * @return {Array}
  84. */
  85. patternMatch: function(pattern) {
  86. var instance = this;
  87. var results = [];
  88. instance._patternMatch(instance._root, pattern, 0, results);
  89. return results;
  90. },
  91. /**
  92. * Searches for a prefix in the tree.
  93. *
  94. * @method prefixSearch
  95. * @param prefix
  96. * @return {Array}
  97. */
  98. prefixSearch: function(prefix) {
  99. var instance = this;
  100. var results = [];
  101. var node = instance._search(instance._root, prefix, 0);
  102. if (node) {
  103. instance._inOrderTraversal(node.get('child'), results);
  104. }
  105. return results;
  106. },
  107. /**
  108. * Traversals a tree.
  109. *
  110. * @method _inOrderTraversal
  111. * @param node
  112. * @param results
  113. * @protected
  114. */
  115. _inOrderTraversal: function(node, results) {
  116. var instance = this;
  117. if (!Lang.isValue(node)) {
  118. return;
  119. }
  120. instance._inOrderTraversal(node.get('smallerNode'), results);
  121. if (node.isEndOfWord()) {
  122. results.push(node.get('word'));
  123. }
  124. instance._inOrderTraversal(node.get('child'), results);
  125. instance._inOrderTraversal(node.get('largerNode'), results);
  126. },
  127. /**
  128. * Insert a node in the tree.
  129. *
  130. * @method _insert
  131. * @param node
  132. * @param word
  133. * @param index
  134. * @protected
  135. */
  136. _insert: function(node, word, index) {
  137. var instance = this;
  138. var character = word.charAt(index);
  139. if (Lang.isValue(node)) {
  140. if (character === node.get('character')) {
  141. if (index + 1 < word.length) {
  142. node.set('child', instance._insert(node.get('child'), word, index + 1));
  143. }
  144. else {
  145. node.set('word', word);
  146. }
  147. }
  148. else if (character < node.get('character')) {
  149. node.set('smallerNode', instance._insert(node.get('smallerNode'), word, index));
  150. }
  151. else {
  152. node.set('largerNode', instance._insert(node.get('largerNode'), word, index));
  153. }
  154. }
  155. else {
  156. node = instance._insert(
  157. new A.TernarySearchNode({
  158. character: character
  159. }),
  160. word,
  161. index
  162. );
  163. }
  164. return node;
  165. },
  166. /**
  167. * Recursive search for a pattern in the tree.
  168. *
  169. * @method _patternMatch
  170. * @param node
  171. * @param pattern
  172. * @param index
  173. * @param results
  174. * @protected
  175. */
  176. _patternMatch: function(node, pattern, index, results) {
  177. var instance = this;
  178. if (Lang.isValue(node)) {
  179. var character = pattern.charAt(index);
  180. var nodeCharacter = node.get('character');
  181. var patternChar = TernarySearchTree.PATTERN_CHAR;
  182. if (character === patternChar || character < nodeCharacter) {
  183. instance._patternMatch(node.get('smallerNode'), pattern, index, results);
  184. }
  185. if (character === patternChar || character === nodeCharacter) {
  186. if (index + 1 < pattern.length) {
  187. instance._patternMatch(node.get('child'), pattern, index + 1, results);
  188. }
  189. else if (node.isEndOfWord()) {
  190. results.push(node.get('word'));
  191. }
  192. }
  193. if (character === patternChar || character > nodeCharacter) {
  194. instance._patternMatch(node.get('largerNode'), pattern, index, results);
  195. }
  196. }
  197. },
  198. /**
  199. * Recursive search for a node in the tree.
  200. *
  201. * @method _search
  202. * @param node
  203. * @param word
  204. * @param index
  205. * @protected
  206. */
  207. _search: function(node, word, index) {
  208. var instance = this;
  209. var result = node;
  210. if (Lang.isValue(node)) {
  211. var character = word.charAt(index);
  212. var nodeCharacter = node.get('character');
  213. if (character === nodeCharacter) {
  214. if (index + 1 < word.length) {
  215. result = instance._search(node.get('child'), word, index + 1);
  216. }
  217. }
  218. else if (character < nodeCharacter) {
  219. result = instance._search(node.get('smallerNode'), word, index);
  220. }
  221. else {
  222. result = instance._search(node.get('largerNode'), word, index);
  223. }
  224. }
  225. return result;
  226. }
  227. }
  228. });
  229. TernarySearchTree.PATTERN_CHAR = '?';
  230. A.TernarySearchTree = TernarySearchTree;