import Comparator from '../../utils/comparator/Comparator'; export default class BinaryTreeNode { /** * @param {*} [value] - node value. * @param {Object} meta - any meta information that needs to be attached to the node. */ constructor(value = null, meta = {}) { this.left = null; this.right = null; this.parent = null; this.value = value; this.meta = meta; // This comparator is used to compare binary tree nodes with each other. this.nodeComparator = new Comparator(); } /** * @return {number} */ get leftHeight() { if (!this.left) { return 0; } return this.left.height + 1; } /** * @return {number} */ get rightHeight() { if (!this.right) { return 0; } return this.right.height + 1; } /** * @return {number} */ get height() { return Math.max(this.leftHeight, this.rightHeight); } /** * @return {number} */ get balanceFactor() { return this.leftHeight - this.rightHeight; } /** * @param {BinaryTreeNode} node * @return {BinaryTreeNode} */ setLeft(node) { // Reset parent for left node since it is going to be detached. if (this.left) { this.left.parent = null; } // Attach new node to the left. this.left = node; // Make current node to be a parent for new left one. if (this.left) { this.left.parent = this; } return this; } /** * @param {BinaryTreeNode} node * @return {BinaryTreeNode} */ setRight(node) { // Reset parent for right node since it is going to be detached. if (this.right) { this.right.parent = null; } // Attach new node to the right. this.right = node; // Make current node to be a parent for new right one. if (node) { this.right.parent = this; } return this; } /** * @param {BinaryTreeNode} nodeToRemove * @return {boolean} */ removeChild(nodeToRemove) { if (this.left && this.nodeComparator.equal(this.left, nodeToRemove)) { this.left = null; return true; } if (this.right && this.nodeComparator.equal(this.right, nodeToRemove)) { this.right = null; return true; } return false; } /** * @param {BinaryTreeNode} nodeToReplace * @param {BinaryTreeNode} replacementNode * @return {boolean} */ replaceChild(nodeToReplace, replacementNode) { if (!nodeToReplace || !replacementNode) { return false; } if (this.left && this.nodeComparator.equal(this.left, nodeToReplace)) { this.left = replacementNode; return true; } if (this.right && this.nodeComparator.equal(this.right, nodeToReplace)) { this.right = replacementNode; return true; } return false; } /** * @return {*[]} */ traverseInOrder() { let traverse = []; // Add left node. if (this.left) { traverse = traverse.concat(this.left.traverseInOrder()); } // Add root. traverse.push(this.value); // Add right node. if (this.right) { traverse = traverse.concat(this.right.traverseInOrder()); } return traverse; } /** * @param {string} property * @param {*} value * @return {BinaryTreeNode} */ setMeta(property, value) { this.meta[property] = value; return this; } /** * @param property * @return {*} */ getMeta(property) { if (!this.meta || !Object.prototype.hasOwnProperty.call(this.meta, property)) { return null; } return this.meta[property]; } /** * @return {string} */ toString() { return this.traverseInOrder().toString(); } }