2018-06-22 08:22:12 +03:00

220 lines
4.4 KiB
JavaScript

import Comparator from '../../utils/comparator/Comparator';
import HashTable from '../hash-table/HashTable';
export default class BinaryTreeNode {
/**
* @param {*} [value] - node value.
*/
constructor(value = null) {
this.left = null;
this.right = null;
this.parent = null;
this.value = value;
// Any node related meta information may be stored here.
this.meta = new HashTable();
// 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;
}
/**
* Get parent's sibling if it exists.
* @return {BinaryTreeNode}
*/
get uncle() {
// Check if current node has parent.
if (!this.parent) {
return undefined;
}
// Check if current node has grand-parent.
if (!this.parent.parent) {
return undefined;
}
// Check if grand-parent has two children.
if (!this.parent.parent.left || !this.parent.parent.right) {
return undefined;
}
// So for now we know that current node has grand-parent and this
// grand-parent has two children. Let's find out who is the uncle.
if (this.nodeComparator.equal(this.parent, this.parent.parent.left)) {
// Right one is an uncle.
return this.parent.parent.right;
}
// Left one is an uncle.
return this.parent.parent.left;
}
/**
* @param {*} value
* @return {BinaryTreeNode}
*/
setValue(value) {
this.value = value;
return this;
}
/**
* @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;
}
/**
* @param {BinaryTreeNode} sourceNode
* @param {BinaryTreeNode} targetNode
*/
static copyNode(sourceNode, targetNode) {
targetNode.setValue(sourceNode.value);
targetNode.setLeft(sourceNode.left);
targetNode.setRight(sourceNode.right);
}
/**
* @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;
}
/**
* @return {string}
*/
toString() {
return this.traverseInOrder().toString();
}
}