Implementing a Binary Tree

If I had to pick the single most important topic in software development, it would be data structures. One of the most common and easiest ones is a tree — a hierarchical data structure. In this article, let’s explore Trees in Java.

  • What is a Binary Tree?
  • Types of Binary Tree
  • Binary Tree Implementation
  • Tree Traversals
  • Applications of Binary Tree

What is a Binary Tree?

A binary tree is a data structure that allows two nodes to be linked together by a path from the root to the leftmost child, and from the leftmost child to the rightmost child. The path is called a path from the root to the leftmost child, and from the leftmost child to the rightmost child.

A binary tree has the following properties:

  • Each node has at most two children
  • The left child of a node is less than the right child of a node
  • The right child of a node is greater than the left child of a node
  • A node is a leaf node if it has no children

Examples of coding problems using trees:

What is the difference between a binary tree and a binary search tree?

A binary tree is a data structure that allows two nodes to be linked together by a path from the root to the leftmost child, and from the leftmost child to the rightmost child. The path is called a path from the root to the leftmost child, and from the leftmost child to the rightmost child.

A binary search tree is a data structure that allows two nodes to be linked together by a path from the root to the leftmost child, and from the leftmost child to the rightmost child, such that the left child is less than the right child.

Each data element stored in a tree structure called a node. A Tree node contains the following parts:
1. Data

2. Pointer to left child

3. Pointer to the right child

  • Binary search trees support many dynamic-set operations, including SEARCH, MINIMUM, MAXIMUM, PREDECESSOR, SUCCESSOR, INSERT and DELETE.
  • Basic operations on a binary search tree take time proportional to the height of the tree – which is O(lg n) for a complete binary tree with n nodes.
  • In practice, we can’t always guarantee that binary search trees are built randomly – but there are variations (like red-black trees) with good guaranteed worst-case performance on basic operations.
  • After presenting the basic properties of binary search trees, the following sections show how to walk a binary search tree to print its values in sorted order; how to find a value in a binary search; minimum or maximum element; predecessor or successor of an element; insert into or delete from a binary search tree.

We can represent a tree node using class. Below is an example of a tree node with integer data.

class Node {
    constructor(value) {
        this.value = value;
        this.left = null;
        this.right = null;
    }
}
class Node {
 
    int value;
    Node left;
    Node right;
 
    Node(int value) {
        this.value = value;
        left = null;
        right = null;
    }
}

What are the Types of Binary Trees?

The three types of binary trees are full, complete, and perfect.

A full binary tree is a binary tree in which every node has either zero or two children. A full binary tree is also sometimes called a proper or strict binary tree.

A complete binary tree is a binary tree in which every level of the tree is fully filled, except for possibly the last level. The last level of a complete binary tree is filled from left to right. explain a perfect binary tree A perfect binary tree is a binary tree in which all of the leaves are at the same level, and all of the internal nodes have two children.

A perfect binary tree is a binary tree in which all of the leaves are at the same level, and all of the internal nodes have two children.

Implementing a binary tree.

We will use an auxiliary Node class to store int values and keep references to each child. The first step is to find the place where we want to add the new node in order to keep the tree sorted. To do this, we will follow these rules starting from the root node:

– If the value to be added is smaller than the root value, we will go to the left subtree.

– If the value to be added is larger than the root value, we will go to the right subtree.

– If we reach a leaf node, it means we have found the place to add the new node.

Let’s do the implementation in JavaScript we will use functional programming first:

function BinarySearchTree() { 
 
    var root = null; 

    this.insert = function(value){ 
        if (root === null){ 
            root = new Node(value); 
        } 
        else { 
            insertNode(root, value); 
        } 
    } 

    this.remove = function(value){ 
        root = removeNode(root, value); 
    } 

    this.search = function(value){ 
        return searchNode(root, value); 
    } 

    this.inorder = function(){ 
        inorderTraverseNode(root); 
    } 

    this.preorder = function(){ 
        preorderTraverseNode(root); 
    } 

    this.postorder = function(){ 
        postorderTraverseNode(root); 
    } 

    this.min = function(){ 
        return minNode(root); 
    } 

    this.max = function(){ 
        return maxNode(root); 
    } 
} 

function insertNode(node, newVal) { 
    if (newVal < node.value) { 
        if (node.left === null) { 
            node.left = new Node(newVal); 
        } 
        else { 
            insertNode(node.left, newVal); 
        } 
    } 
    else { 
        if (node.right === null) { 
            node.right = new Node(newVal); 
        } 
        else { 
            insertNode(node.right, newVal); 
        } 
    } 
} 

function removeNode(node, key) { 
    if (node === null) { 
        return null; 
    } 
    if (key < node.value) { 
        node.left = removeNode(node.left, key); 
        return node; 
    } 
    else if (key > node.value) { 
        node.right = removeNode(node.right, key); 
        return node; 
    } 
    else { 
        if (node.left === null && node.right === null) { 
            node = null; 
            return node; 
        } 
        if (node.left === null) { 
            node = node.right; 
            return node; 
        } 
        else if (node.right === null) { 
            node = node.left; 
            return node; 
        } 
        var aux = minNode(node.right); 
        node.value = aux.value; 
        node.right = removeNode(node.right, aux.value); 
        return node; 
    } 
} 

function searchNode(node, key) { 
    if (node === null) { 
        return false; 
    } 
    if (key < node.value) { 
        return searchNode(node.left, key); 
    } 
    else if (key > node.value) { 
        return searchNode(node.right, key); 
    } 
    else { 
        return true; 
    } 
} 

function inorderTraverseNode(node) { 
    if (node !== null) { 
        inorderTraverseNode(node.left); 
        console.log(node.value); 
        inorderTraverseNode(node.right); 
    } 
} 

function preorderTraverseNode(node) { 
    if (node !== null) { 
        console.log(node.value); 
        preorderTraverseNode(node.left); 
        preorderTraverseNode(node.right); 
    } 
} 

function postorderTraverseNode(node) { 
    if (node !== null) { 
        postorderTraverseNode(node.left); 
        postorderTraverseNode(node.right); 
        console.log(node.value); 
    } 
} 

function minNode(node) { 
    if (node) { 
        while (node && node.left !== null) { 
            node = node.left; 
        } 

        return node.value; 
    } 

    return null; 
} 

function maxNode(node) { 
    if (node) { 
        while (node && node.right !== null) { 
            node = node.right; 
        } 

        return node.value; 
    } 
    return null; 
}

Using JavaScript Class

class Node {
  constructor(value) {
    this.value = value;
    this.left = null;
    this.right = null;
  }
}

class BinaryTree {
  constructor() {
    this.root = null;
  }

  // function to insert a node in the tree
  insert(value) {
    const newNode = new Node(value);

    // if the tree is empty, set the root to the new node
    if (this.root === null) {
      this.root = newNode;
    } else {
      // find the correct position in the tree and insert the new node
      this.insertNode(this.root, newNode);
    }
  }

  // helper function to insert a node in the correct position in the tree
  insertNode(node, newNode) {
    // if the value of the new node is less than the value of the current node, insert it in the left subtree
    if (newNode.value < node.value) {
      // if the left child of the current node is null, set the left child to the new node
      if (node.left === null) {
        node.left = newNode;
      } else {
        // if the left child is not null, recurse through the left subtree
        this.insertNode(node.left, newNode);
      }
    } else {
      // if the value of the new node is greater than or equal to the value of the current node, insert it in the right subtree
      if (node.right === null) {
        node.right = newNode;
      } else {
        // if the right child is not null, recurse through the right subtree
        this.insertNode(node.right, newNode);
      }
    }
  }

  // function to remove a node from the tree
  remove(value) {
    // if the tree is empty, return null
    if (this.root === null) {
      return null;
    } else {
      // find the node to be removed and remove it
      this.root = this.removeNode(this.root, value);
    }
  }

  // helper function to remove a node from the tree
  removeNode(node, value) {
    // if the tree is empty, return null
    if (node === null) {
      return null;
    }

    // if the value to be removed is less than the value of the current node, recurse through the left subtree
    if (value < node.value) {
      node.left = this.removeNode(node.left, value);
      return node;
    } else if (value > node.value) {
      // if the value to be removed is greater than the value of the current node, recurse through the right subtree
      node.right = this.removeNode(node.right, value);
      return node;
    } else {
      // if the value to be removed is equal to the value of the current node, remove the node

      // if the node to be removed has no children, set it to null
      if (node.left === null && node.right === null) {
        node = null;
        return node;
      }

      // if the node to be removed has no left child, set the node to its right child
      if (node.left === null) {
        node = node.right;
        return node;
      } else if (node.right === null) {
        // if the node to be removed has no right child, set the node to its left child
        node = node.left;
        return node;
      }

      // if the node to be removed has two children, find the minimum value in the right subtree
      const minValue = this.findMinValue(node.right);
      node.value = minValue;

      // remove the minimum value from the right subtree
      node.right = this.removeNode(node.right, minValue);
      return node;
    }
  }

  // function to find the minimum value in a subtree
  findMinValue(node) {
    if (node.left === null) {
      return node.value;
    } else {
      return this.findMinValue(node.left);
    }
  }

  // function to search for a value in the tree
  search(value) {
    // if the tree is empty, return false
    if (this.root === null) {
      return false;
    } else {
      // search for the value in the tree
      return this.searchNode(this.root, value);
    }
  }

  // helper function to search for a value in the tree
  searchNode(node, value) {
    // if the tree is empty, return false
    if (node === null) {
      return false;
    }

    // if the value is less than the value of the current node, recurse through the left subtree
    if (value < node.value) {
      return this.searchNode(node.left, value);
    } else if (value > node.value) {
      // if the value is greater than the value of the current node, recurse through the right subtree
      return this.searchNode(node.right, value);
    } else {
      // if the value is equal to the value of the current node, return true
      return true;
    }
  }
}

Related

How to 10x Your LLM Prompting With DSPy

Tired of spending countless hours tweaking prompts for large...

Google Announces A Cost Effective Gemini Flash

At Google's I/O event, the company unveiled Gemini Flash,...

WordPress vs Strapi: Choosing the Right CMS for Your Needs

With the growing popularity of headless CMS solutions, developers...

JPA vs. JDBC: Comparing the two DB APIs

Introduction The eternal battle rages on between two warring database...

Meta Introduces V-JEPA

The V-JEPA model, proposed by Yann LeCun, is a...

Subscribe to our AI newsletter. Get the latest on news, models, open source and trends.
Don't worry, we won't spam. 😎

You have successfully subscribed to the newsletter

There was an error while trying to send your request. Please try again.

Lusera will use the information you provide on this form to be in touch with you and to provide updates and marketing.