mirror of
https://github.com/trekhleb/javascript-algorithms.git
synced 2025-12-08 19:06:00 +00:00
220 lines
4.4 KiB
JavaScript
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();
|
|
}
|
|
}
|