Tree
Data Structure · Core
Step through it: Binary Tree Traversal pattern
Step 1 of 5
A tree has no single first-to-last order, so we pick one. The three common orders differ only in when a node is visited compared with its children.
Step 2 of 5
Pre-order: the node first, then left, then right. Good for copying a tree.
Step 3 of 5
In-order: left, then the node, then right. On a binary search tree this gives the values in sorted order.
Step 4 of 5
Post-order: left, right, then the node. Children come before their parent, so it is the order for deleting a tree or adding up sizes.
Step 5 of 5
Your turn.
- Binary Search Tree
- AVL Tree
- Red-Black Tree
- Segment Tree - with min/max/sum range queries examples
- Fenwick Tree (Binary Indexed Tree)
In computer science, a tree is a widely used abstract data type (ADT) — or data structure implementing this ADT—that simulates a hierarchical tree structure, with a root value and subtrees of children with a parent node, represented as a set of linked nodes.
A tree data structure can be defined recursively (locally) as a collection of nodes (starting at a root node), where each node is a data structure consisting of a value, together with a list of references to nodes (the "children"), with the constraints that no reference is duplicated, and none points to the root.
A simple unordered tree; in this diagram, the node labeled 3 has two children, labeled 2 and 6, and one parent, labeled 2. The root node, at the top, has no parent.

Made with okso.app
Code
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();
}
}References
Practice
Binary Tree Traversal
- Binary Tree Inorder TraversalEasy
- Binary Tree Preorder TraversalEasy
- Binary Tree Postorder TraversalEasy
- Same TreeEasy
- Symmetric TreeEasy
- Invert Binary TreeEasy
- Subtree of Another TreeEasy
- Merge Two Binary TreesEasy
- Construct Binary Tree from Preorder and Inorder TraversalMedium
- Construct Binary Tree from Inorder and Postorder TraversalMedium
- Validate Binary Search TreeMedium
- Kth Smallest Element in a BSTMedium
- Flatten Binary Tree to Linked ListMedium
- Lowest Common Ancestor of a Binary TreeMedium
- Binary Search Tree IteratorMedium
- Recover Binary Search TreeMedium
- Serialize and Deserialize Binary TreeHard
- Binary Tree Maximum Path SumHard
Spotted a mistake or something unclear? Report it on GitHub.