treenode.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. // Copyright 2010 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 Generic tree node data structure with arbitrary number of child
  16. * nodes.
  17. *
  18. */
  19. goog.provide('goog.structs.TreeNode');
  20. goog.require('goog.array');
  21. goog.require('goog.asserts');
  22. goog.require('goog.structs.Node');
  23. /**
  24. * Generic tree node data structure with arbitrary number of child nodes.
  25. * It is possible to create a dynamic tree structure by overriding
  26. * {@link #getParent} and {@link #getChildren} in a subclass. All other getters
  27. * will automatically work.
  28. *
  29. * @param {KEY} key Key.
  30. * @param {VALUE} value Value.
  31. * @constructor
  32. * @extends {goog.structs.Node<KEY, VALUE>}
  33. * @template KEY, VALUE
  34. */
  35. goog.structs.TreeNode = function(key, value) {
  36. goog.structs.Node.call(this, key, value);
  37. /**
  38. * Reference to the parent node or null if it has no parent.
  39. * @private {goog.structs.TreeNode<KEY, VALUE>}
  40. */
  41. this.parent_ = null;
  42. /**
  43. * Child nodes or null in case of leaf node.
  44. * @private {Array<!goog.structs.TreeNode<KEY, VALUE>>}
  45. */
  46. this.children_ = null;
  47. };
  48. goog.inherits(goog.structs.TreeNode, goog.structs.Node);
  49. /**
  50. * Constant for empty array to avoid unnecessary allocations.
  51. * @private
  52. */
  53. goog.structs.TreeNode.EMPTY_ARRAY_ = [];
  54. /**
  55. * @return {!goog.structs.TreeNode} Clone of the tree node without its parent
  56. * and child nodes. The key and the value are copied by reference.
  57. * @override
  58. */
  59. goog.structs.TreeNode.prototype.clone = function() {
  60. return new goog.structs.TreeNode(this.getKey(), this.getValue());
  61. };
  62. /**
  63. * @return {!goog.structs.TreeNode} Clone of the subtree with this node as root.
  64. */
  65. goog.structs.TreeNode.prototype.deepClone = function() {
  66. var clone = this.clone();
  67. this.forEachChild(function(child) { clone.addChild(child.deepClone()); });
  68. return clone;
  69. };
  70. /**
  71. * @return {goog.structs.TreeNode<KEY, VALUE>} Parent node or null if it has no
  72. * parent.
  73. */
  74. goog.structs.TreeNode.prototype.getParent = function() {
  75. return this.parent_;
  76. };
  77. /**
  78. * @return {boolean} Whether the node is a leaf node.
  79. */
  80. goog.structs.TreeNode.prototype.isLeaf = function() {
  81. return !this.getChildCount();
  82. };
  83. /**
  84. * Tells if the node is the last child of its parent. This method helps how to
  85. * connect the tree nodes with lines: L shapes should be used before the last
  86. * children and |- shapes before the rest. Schematic tree visualization:
  87. *
  88. * <pre>
  89. * Node1
  90. * |-Node2
  91. * | L-Node3
  92. * | |-Node4
  93. * | L-Node5
  94. * L-Node6
  95. * </pre>
  96. *
  97. * @return {boolean} Whether the node has parent and is the last child of it.
  98. */
  99. goog.structs.TreeNode.prototype.isLastChild = function() {
  100. var parent = this.getParent();
  101. return Boolean(parent && this == goog.array.peek(parent.getChildren()));
  102. };
  103. /**
  104. * @return {!Array<!goog.structs.TreeNode<KEY, VALUE>>} Immutable child nodes.
  105. */
  106. goog.structs.TreeNode.prototype.getChildren = function() {
  107. return this.children_ || goog.structs.TreeNode.EMPTY_ARRAY_;
  108. };
  109. /**
  110. * Gets the child node of this node at the given index.
  111. * @param {number} index Child index.
  112. * @return {goog.structs.TreeNode<KEY, VALUE>} The node at the given index or
  113. * null if not found.
  114. */
  115. goog.structs.TreeNode.prototype.getChildAt = function(index) {
  116. return this.getChildren()[index] || null;
  117. };
  118. /**
  119. * @return {number} The number of children.
  120. */
  121. goog.structs.TreeNode.prototype.getChildCount = function() {
  122. return this.getChildren().length;
  123. };
  124. /**
  125. * @return {number} The number of ancestors of the node.
  126. */
  127. goog.structs.TreeNode.prototype.getDepth = function() {
  128. var depth = 0;
  129. var node = this;
  130. while (node.getParent()) {
  131. depth++;
  132. node = node.getParent();
  133. }
  134. return depth;
  135. };
  136. /**
  137. * @return {!Array<!goog.structs.TreeNode<KEY, VALUE>>} All ancestor nodes in
  138. * bottom-up order.
  139. */
  140. goog.structs.TreeNode.prototype.getAncestors = function() {
  141. var ancestors = [];
  142. var node = this.getParent();
  143. while (node) {
  144. ancestors.push(node);
  145. node = node.getParent();
  146. }
  147. return ancestors;
  148. };
  149. /**
  150. * @return {!goog.structs.TreeNode<KEY, VALUE>} The root of the tree structure,
  151. * i.e. the farthest ancestor of the node or the node itself if it has no
  152. * parents.
  153. */
  154. goog.structs.TreeNode.prototype.getRoot = function() {
  155. var root = this;
  156. while (root.getParent()) {
  157. root = root.getParent();
  158. }
  159. return root;
  160. };
  161. /**
  162. * Builds a nested array structure from the node keys in this node's subtree to
  163. * facilitate testing tree operations that change the hierarchy.
  164. * @return {!Array<KEY>} The structure of this node's descendants as nested
  165. * array of node keys. The number of unclosed opening brackets up to a
  166. * particular node is proportional to the indentation of that node in the
  167. * graphical representation of the tree. Example:
  168. * <pre>
  169. * this
  170. * |- child1
  171. * | L- grandchild
  172. * L- child2
  173. * </pre>
  174. * is represented as ['child1', ['grandchild'], 'child2'].
  175. */
  176. goog.structs.TreeNode.prototype.getSubtreeKeys = function() {
  177. var ret = [];
  178. this.forEachChild(function(child) {
  179. ret.push(child.getKey());
  180. if (!child.isLeaf()) {
  181. ret.push(child.getSubtreeKeys());
  182. }
  183. });
  184. return ret;
  185. };
  186. /**
  187. * Tells whether this node is the ancestor of the given node.
  188. * @param {!goog.structs.TreeNode<KEY, VALUE>} node A node.
  189. * @return {boolean} Whether this node is the ancestor of {@code node}.
  190. */
  191. goog.structs.TreeNode.prototype.contains = function(node) {
  192. var current = node;
  193. do {
  194. current = current.getParent();
  195. } while (current && current != this);
  196. return Boolean(current);
  197. };
  198. /**
  199. * Finds the deepest common ancestor of the given nodes. The concept of
  200. * ancestor is not strict in this case, it includes the node itself.
  201. * @param {...!goog.structs.TreeNode<KEY, VALUE>} var_args The nodes.
  202. * @return {goog.structs.TreeNode<KEY, VALUE>} The common ancestor of the nodes
  203. * or null if they are from different trees.
  204. * @template KEY, VALUE
  205. */
  206. goog.structs.TreeNode.findCommonAncestor = function(var_args) {
  207. /** @type {goog.structs.TreeNode} */
  208. var ret = arguments[0];
  209. if (!ret) {
  210. return null;
  211. }
  212. var retDepth = ret.getDepth();
  213. for (var i = 1; i < arguments.length; i++) {
  214. /** @type {goog.structs.TreeNode} */
  215. var node = arguments[i];
  216. var depth = node.getDepth();
  217. while (node != ret) {
  218. if (depth <= retDepth) {
  219. ret = ret.getParent();
  220. retDepth--;
  221. }
  222. if (depth > retDepth) {
  223. node = node.getParent();
  224. depth--;
  225. }
  226. }
  227. }
  228. return ret;
  229. };
  230. /**
  231. * Returns a node whose key matches the given one in the hierarchy rooted at
  232. * this node. The hierarchy is searched using an in-order traversal.
  233. * @param {KEY} key The key to search for.
  234. * @return {goog.structs.TreeNode<KEY, VALUE>} The node with the given key, or
  235. * null if no node with the given key exists in the hierarchy.
  236. */
  237. goog.structs.TreeNode.prototype.getNodeByKey = function(key) {
  238. if (this.getKey() == key) {
  239. return this;
  240. }
  241. var children = this.getChildren();
  242. for (var i = 0; i < children.length; i++) {
  243. var descendant = children[i].getNodeByKey(key);
  244. if (descendant) {
  245. return descendant;
  246. }
  247. }
  248. return null;
  249. };
  250. /**
  251. * Traverses all child nodes.
  252. * @param {function(this:THIS, !goog.structs.TreeNode<KEY, VALUE>, number,
  253. * !Array<!goog.structs.TreeNode<KEY, VALUE>>)} f Callback function. It
  254. * takes the node, its index and the array of all child nodes as arguments.
  255. * @param {THIS=} opt_this The object to be used as the value of {@code this}
  256. * within {@code f}.
  257. * @template THIS
  258. */
  259. goog.structs.TreeNode.prototype.forEachChild = function(f, opt_this) {
  260. goog.array.forEach(this.getChildren(), f, opt_this);
  261. };
  262. /**
  263. * Traverses all child nodes recursively in preorder.
  264. * @param {function(this:THIS, !goog.structs.TreeNode<KEY, VALUE>)} f Callback
  265. * function. It takes the node as argument.
  266. * @param {THIS=} opt_this The object to be used as the value of {@code this}
  267. * within {@code f}.
  268. * @template THIS
  269. */
  270. goog.structs.TreeNode.prototype.forEachDescendant = function(f, opt_this) {
  271. var children = this.getChildren();
  272. for (var i = 0; i < children.length; i++) {
  273. f.call(opt_this, children[i]);
  274. children[i].forEachDescendant(f, opt_this);
  275. }
  276. };
  277. /**
  278. * Traverses the subtree with the possibility to skip branches. Starts with
  279. * this node, and visits the descendant nodes depth-first, in preorder.
  280. * @param {function(this:THIS, !goog.structs.TreeNode<KEY, VALUE>):
  281. * (boolean|undefined)} f Callback function. It takes the node as argument.
  282. * The children of this node will be visited if the callback returns true or
  283. * undefined, and will be skipped if the callback returns false.
  284. * @param {THIS=} opt_this The object to be used as the value of {@code this}
  285. * within {@code f}.
  286. * @template THIS
  287. */
  288. goog.structs.TreeNode.prototype.traverse = function(f, opt_this) {
  289. if (f.call(opt_this, this) !== false) {
  290. var children = this.getChildren();
  291. for (var i = 0; i < children.length; i++) {
  292. children[i].traverse(f, opt_this);
  293. }
  294. }
  295. };
  296. /**
  297. * Sets the parent node of this node. The callers must ensure that the parent
  298. * node and only that has this node among its children.
  299. * @param {goog.structs.TreeNode<KEY, VALUE>} parent The parent to set. If
  300. * null, the node will be detached from the tree.
  301. * @protected
  302. */
  303. goog.structs.TreeNode.prototype.setParent = function(parent) {
  304. this.parent_ = parent;
  305. };
  306. /**
  307. * Appends a child node to this node.
  308. * @param {!goog.structs.TreeNode<KEY, VALUE>} child Orphan child node.
  309. */
  310. goog.structs.TreeNode.prototype.addChild = function(child) {
  311. this.addChildAt(child, this.children_ ? this.children_.length : 0);
  312. };
  313. /**
  314. * Inserts a child node at the given index.
  315. * @param {!goog.structs.TreeNode<KEY, VALUE>} child Orphan child node.
  316. * @param {number} index The position to insert at.
  317. */
  318. goog.structs.TreeNode.prototype.addChildAt = function(child, index) {
  319. goog.asserts.assert(!child.getParent());
  320. child.setParent(this);
  321. this.children_ = this.children_ || [];
  322. goog.asserts.assert(index >= 0 && index <= this.children_.length);
  323. goog.array.insertAt(this.children_, child, index);
  324. };
  325. /**
  326. * Replaces a child node at the given index.
  327. * @param {!goog.structs.TreeNode<KEY, VALUE>} newChild Child node to set. It
  328. * must not have parent node.
  329. * @param {number} index Valid index of the old child to replace.
  330. * @return {!goog.structs.TreeNode<KEY, VALUE>} The original child node,
  331. * detached from its parent.
  332. */
  333. goog.structs.TreeNode.prototype.replaceChildAt = function(newChild, index) {
  334. goog.asserts.assert(
  335. !newChild.getParent(), 'newChild must not have parent node');
  336. var children = this.getChildren();
  337. var oldChild = children[index];
  338. goog.asserts.assert(oldChild, 'Invalid child or child index is given.');
  339. oldChild.setParent(null);
  340. children[index] = newChild;
  341. newChild.setParent(this);
  342. return oldChild;
  343. };
  344. /**
  345. * Replaces the given child node.
  346. * @param {!goog.structs.TreeNode<KEY, VALUE>} newChild New node to replace
  347. * {@code oldChild}. It must not have parent node.
  348. * @param {!goog.structs.TreeNode<KEY, VALUE>} oldChild Existing child node to
  349. * be replaced.
  350. * @return {!goog.structs.TreeNode<KEY, VALUE>} The replaced child node
  351. * detached from its parent.
  352. */
  353. goog.structs.TreeNode.prototype.replaceChild = function(newChild, oldChild) {
  354. return this.replaceChildAt(
  355. newChild, goog.array.indexOf(this.getChildren(), oldChild));
  356. };
  357. /**
  358. * Removes the child node at the given index.
  359. * @param {number} index The position to remove from.
  360. * @return {goog.structs.TreeNode<KEY, VALUE>} The removed node if any.
  361. */
  362. goog.structs.TreeNode.prototype.removeChildAt = function(index) {
  363. var child = this.children_ && this.children_[index];
  364. if (child) {
  365. child.setParent(null);
  366. goog.array.removeAt(this.children_, index);
  367. if (this.children_.length == 0) {
  368. this.children_ = null;
  369. }
  370. return child;
  371. }
  372. return null;
  373. };
  374. /**
  375. * Removes the given child node of this node.
  376. * @param {goog.structs.TreeNode<KEY, VALUE>} child The node to remove.
  377. * @return {goog.structs.TreeNode<KEY, VALUE>} The removed node if any.
  378. */
  379. goog.structs.TreeNode.prototype.removeChild = function(child) {
  380. return child &&
  381. this.removeChildAt(goog.array.indexOf(this.getChildren(), child));
  382. };
  383. /**
  384. * Removes all child nodes of this node.
  385. */
  386. goog.structs.TreeNode.prototype.removeChildren = function() {
  387. if (this.children_) {
  388. for (var i = 0; i < this.children_.length; i++) {
  389. this.children_[i].setParent(null);
  390. }
  391. this.children_ = null;
  392. }
  393. };