Do You Read Left to Right or Vice Vresa for Binary Nunmbers

Binary Tree With Java Examples

Binary Tree (with Coffee Lawmaking)

Author image

by Sven WoltmannMay 28, 2021

Ii of the most important topics in computer science are sorting and searching data sets. A data structure often used for both is the binary tree and its concrete implementations binary search tree and binary heap.

In this article, y'all will learn:

  • What is a binary tree?
  • What types of binary trees exist?
  • How to implement a binary tree in Java?
  • What operations practice binary copse provide?
  • What are pre-order, in-gild, post-order, and level-order traversal in binary trees?

You can find the source code for the article in this GitHub repository.

Binary Tree Definition

A binary tree is a tree data structure in which each node has at most ii child nodes. The child nodes are chosen left child and right child.

Binary Tree Example

As an instance, a binary tree looks similar this:

Binary tree example
Binary tree example

Binary Tree Terminology

As a developer, you should know the following terms:

  • A node is a structure that contains data and optional references to a left and a right child node (or just kid).
  • The connectedness between two nodes is called an edge.
  • The top node is called the root or root node.
  • A node that has children is an inner node (short: inode) and, at the same time, the parent node of its child(ren).
  • A node without children is chosen an outer node or leaf node, or merely a leafage.
  • A node with only one kid is a half node. Attention: this term exists – in dissimilarity to all others – only for binary copse, not for trees in full general.
  • The number of child nodes is besides chosen the degree of a node.
  • The depth of a node indicates how many levels the node is away from the root. Therefore, the root has a depth of 0, the root's children accept a depth of 1, and so on.
  • The height of a binary tree is the maximum depth of all its nodes.

The post-obit image shows the same binary tree information structure every bit before, labeled with node types, node depth, and binary tree height.

Binary tree data structure with node types
Binary tree data structure with node types

Binary Trees Properties

Before we get to the implementation of binary copse and their operations, allow'due south first briefly look at some special binary tree types.

Full Binary Tree

In a full binary tree, all nodes have either no children or two children.

Full binary tree
Full binary tree

Consummate Binary Tree

In a consummate binary tree, all levels, except possibly the last one, are completely filled. If the last level is not completely filled, then its nodes are arranged equally far to the left equally possible.

Complete binary tree
Complete binary tree

Perfect Binary Tree

A perfect binary tree is a total binary tree in which all leaves have the same depth.

Perfect binary tree of height 3
Perfect binary tree of summit three

A perfect binary tree of height h has n = 2h+1-1 nodes and l = 2h leaves.

At the height of 3, that's xv nodes, viii of which are leaves.

Counterbalanced Binary Tree

In a counterbalanced binary tree, each node's left and right subtrees differ in elevation by at almost one.

Balanced binary tree
Balanced binary tree

Sorted Binary Tree

In a sorted binary tree (also known every bit ordered binary tree), the left subtree of a node contains merely values less than (or equal to) the value of the parent node, and the right subtree contains only values greater than (or equal to) the value of the parent node. Such a data construction is also called a binary search tree.

Binary Tree in Java

For the binary tree implementation in Java, we kickoff define the information construction for the nodes (class Node in the GitHub repository). For simplicity, nosotros use int primitives equally node information. We can, of course, use any other or a generic data blazon; yet, with an int, the code is more readable – and that is most of import for this tutorial.

              

public course Node { int data; Node left; Node right; Node parent; public Node (int information) { this.data = information; } }

Code linguistic communication: Java ( coffee )

The parent reference is non mandatory for storing and displaying the tree. Yet, it is helpful – at to the lowest degree for sure types of binary trees – when deleting nodes.

The binary tree itself initially consists only of the interface BinaryTree and its minimal implementation BaseBinaryTree, which initially contains only a reference to the root node:

              

public interface BinaryTree { Node getRoot () ; } public course BaseBinaryTree implements BinaryTree { Node root; @Override public Node getRoot () { return root; } }

Code language: Java ( java )

Why nosotros bother to define an interface hither will become apparent in the further course of the tutorial.

The binary tree data structure is thus fully divers.

Binary Tree Traversal

An essential operation on binary trees is the traversal of all nodes, i.e., visiting all nodes in a particular club. The most common types of traversal are:

  • Depth-showtime search (pre-lodge, post-order, in-order, reverse in-order traversal)
  • Breadth-first search (level-order traversal)

In the following sections, you will see the different types illustrated by the post-obit example:

Example of binary tree traversal
Example for binary tree traversal

We implement the visiting during traversal using the visitor blueprint pattern, i.due east., we create a company object which we pass to the traversal method.

Depth-First Search in a Binary Tree

In depth-showtime search (DFS), we perform the post-obit iii operations in a specific guild:

  • visiting the current node (from now on referred to as "N),
  • the depth-first search is invoked recursively on the left kid (referred to equally "L"),
  • the depth-offset search is invoked recursively on the right child (referred to as "R").

The standard sequences are:

Binary Tree Pre-Guild Traversal

In pre-order traversal (also known as NLR), traversing is performed in the following club:

  1. visiting the current node "North",
  2. recursive invocation of depth-beginning search on left subtree "L",
  3. recursive invocation of depth-start search on right subtree "R".

The nodes of the case tree are visited in the following club, as shown in the diagram below: 3→1→13→10→eleven→16→15→2

Binary Tree Preorder Traversal
Binary tree pre-club traversal

The code for this is adequately unproblematic (DepthFirstTraversalRecursive form, starting at line 21):

              

private void traversePreOrder (Node node, NodeVisitor visitor) { if (node == naught) { render; } visitor.visit(node); traversePreOrder(node.left, visitor); traversePreOrder(node.correct, visitor); }

Lawmaking language: Java ( java )

You tin either invoke the method directly – in which case you lot must pass the the root node to it – or via the non-static method traversePreOrder() in the aforementioned class (DepthFirstTraversalRecursive, starting at line 17):

              

public void traversePreOrder (NodeVisitor company) { traversePreOrder(tree.getRoot(), company); }

Code linguistic communication: Java ( java )

This requires creating an example of DepthFirstTraversalRecursive, passing a reference to the binary tree to the constructor:

              

new DepthFirstTraversalRecursive(tree).traversePreOrder(visitor);

Code linguistic communication: Java ( coffee )

An iterative implementation is as well possible using a stack (grade DepthFirstTraversalIterative from line 20). The iterative implementations are pretty complex, which is why I practice not print them here.

You can read why I utilise ArrayDeque instead of Stack in iterative tree traversals hither: Why you lot should not use Stack.

Binary Tree Post-Guild Traversal

In mail service-social club traversal (also known as LRN), traversing is performed in the following order:

  1. recursive invocation of depth-first search on left subtree "50",
  2. recursive invocation of depth-first search on right subtree "R",
  3. visiting the current node "Due north".

In this case, the nodes of the example tree are visited in the following order: 13→one→xi→15→2→16→x→3

Binary tree postorder traversal
Binary tree post-social club traversal

You can find the lawmaking in DepthFirstTraversalRecursive starting at line 42:

              

public static void traversePostOrder (Node node, NodeVisitor company) { if (node == null) { return; } traversePostOrder(node.left, visitor); traversePostOrder(node.right, visitor); visitor.visit(node); }

Code language: Coffee ( java )

You lot tin can find the iterative implementation, which is fifty-fifty more than complicated for post-order traversal than for pre-gild traversal, in DepthFirstTraversalIterative starting at line 44.

Binary Tree In-Order Traversal

In-guild traversal (besides known as LNR) traverses the tree in the post-obit society:

  1. recursive invocation of depth-first search on left subtree "L",
  2. visiting the current node "N",
  3. recursive invocation of depth-first search on right subtree "R".

The nodes of the case tree are visited in the following guild: xiii→1→3→11→ten→xv→sixteen→ii

Binary tree inorder traversal
Binary tree in-guild traversal

You will find the recursive lawmaking in DepthFirstTraversalRecursive starting at line 62:

              

public static void traverseInOrder (Node node, NodeVisitor visitor) { if (node == null) { render; } traverseInOrder(node.left, company); company.visit(node); traverseInOrder(node.right, visitor); }

Code language: Java ( java )

See DepthFirstTraversalIterative starting at line 69 for the iterative implementation of in-social club traversal.

In a binary search tree, in-order traversal visits the nodes in the order in which they are sorted.

Binary Tree Contrary In-Order Traversal

Contrary in-order traversal (also known as RNL) traverses the tree in the post-obit reverse order:

  1. recursive invocation of depth-get-go search on right subtree "R",
  2. visiting the current node "North",
  3. recursive invocation of depth-first search on left subtree "L".

The nodes of the sample tree are visited in opposite order to the in-lodge traversal: 2→16→15→x→11→3→1→13

Binary tree reverse inorder traversal
Binary tree contrary in-lodge traversal

You will find the recursive code in DepthFirstTraversalRecursive starting at line 83:

              

public static void traverseReverseInOrder (Node node, NodeVisitor visitor) { if (node == null) { render; } traverseReverseInOrder(node.correct, company); visitor.visit(node); traverseReverseInOrder(node.left, visitor); }

Lawmaking language: Java ( java )

You tin discover the iterative implementation of reverse in-gild traversal in DepthFirstTraversalIterative starting at line 89.

In a binary search tree, contrary in-order traversal visits the nodes in descending sort order.

Binary Tree Level-Lodge Traversal

In breadth-first search (BFS) – too chosen level-order traversal – nodes are visited starting from the root, level by level, from left to correct.

Level-order traversal results in the following sequence: 3→1→ten→13→11→16→xv→2

Binary tree level order traversal
Binary tree level-lodge traversal

To visit the nodes in level-order, we need a queue in which we first insert the root node and and then repeatedly remove the first element, visit it, and add its children to the queue – until the queue is empty once again.

You can notice the code in the BreadthFirstTraversal class:

              

public static void traverseLevelOrder (Node root, NodeVisitor visitor) { if (root == zero) { render; } Queue<Node> queue = new ArrayDeque<>(); queue.add(root); while (!queue.isEmpty()) { Node node = queue.poll(); visitor.visit(node); if (node.left != nothing) { queue.add(node.left); } if (node.right != zip) { queue.add together(node.right); } } }

Code language: Coffee ( java )

You tin discover examples for invoking all traversal types in the traverseTreeInVariousWays() method of the Example1 class.

Binary Tree Operations

Besides traversal, other bones operations on binary trees are the insertion and deletion of nodes.

Search operations are provided by special binary trees such as the binary search tree. Without special backdrop, nosotros tin search a binary tree only by traversing over all nodes and comparing each with the searched element.

Insertion of a Node

When inserting new nodes into a binary tree, nosotros have to distinguish different cases:

Case A: Inserting a Node Beneath a (Half) Leaf

Es ist leicht einen neuen Knoten an ein Blatt oder ein Halbblatt anzuhängen. Hierzu müssen wir lediglich dice left- oder right-Referenz des Parent-Knotens P, an den wir den neuen Knoten North anhängen wollen, auf den neuen Knoten setzen. Wenn wir auch mit parent-Referenzen arbeiten, müssen wir diese im neuen Knoten Due north auf den Parent-Knoten P setzen.

It is like shooting fish in a barrel to append a new node to a leaf or one-half leaf. To do this, we but need to set the left or correct reference of the parent node P, to which we desire to suspend the new node North, to the new node. If nosotros are working with a parent reference, we need to set the new node's parent reference to P.

Binary tree: inserting a new node below a leaf
Inserting a new node beneath a leafage
Binary tree: inserting a new node below a half leaf
Inserting a new node beneath a half leaf

Case B: Inserting a Node Between Inner Node and Its Kid

But how do you lot go about inserting a node between an inner node and one of its children?

Binary tree: inserting a new node below an inner node
Inserting a new node below an inner node

This is only possible by reorganizing the tree. How exactly the tree is reorganized depends on the concrete type of binary tree.

In this tutorial, we implement a very simple binary tree and proceed as follows for the reorganization:

  • If the new node North is to exist inserted equally a left child below the inner node P, then P'southward current left subtree 50 is set every bit a left kid below the new node Northward. Accordingly, the parent of Fifty is gear up to N, and the parent of N is ready to P.
  • If the new node Northward is to exist inserted every bit a correct child below the inner node P, then P'south current right subtree R is set equally a right kid below the new node N. Accordingly, the parent of R is set to N, and the parent of Northward is set to P.

The following diagram shows the 2d example: We insert the new node Due north between P and R:

Binary tree: inserting a new node between an inner node and its child
Inserting a new node betwixt an inner node and its child

This is – as mentioned – a very elementary implementation. In the example above, this results in a highly unbalanced binary tree.

Specific binary trees take a unlike approach here to maintain a tree structure that satisfies the particular properties of the binary tree in question (sorting, balancing, etc.).

Inserting a Binary Tree Node – Java Source Code

Hither you tin can see the lawmaking for inserting a new node with the given data below the given parent node to the specified side (left or right) using the reorganization strategy divers in the previous section (class SimpleBinaryTree starting at line 18).

(The switch expression with the curly braces was introduced in Java 12/13.)

              

public Node insertNode (int data, Node parent, Side side) { var node = new Node(information); node.parent = parent; switch (side) { example LEFT -> { if (parent.left != null) { node.left = parent.left; node.left.parent = node; } parent.left = node; } case Right -> { if (parent.correct != zip) { node.right = parent.right; node.right.parent = node; } parent.right = node; } default -> throw new IllegalStateException(); } return node; }

Code language: Java ( coffee )

In the createSampleTree() method of the Example1 class, you tin can run into how to create the sample binary tree from the beginning of this article.

Deletion of a Node

Too, when deleting a node, nosotros have to distinguish different cases.

Case A: Deleting a Node Without Children (Foliage)

If the node N to be deleted is a leafage, i.e., has no children itself, then the node is simply removed. To exercise this, we check whether the node is the left or right child of the parent P and set P'due south left or right reference to zero accordingly.

Binary tree: deleting a leaf node
Deleting a leaf node from a binary tree

Case B: Deleting a Node With One Child (Half Leaf)

If the node N to be deleted has a child C itself, then the child moves upward to the deleted position. Again, we check whether node North is the left or right child of its parent P. And so, accordingly, nosotros set up the left or correct reference of P to N's child C (the previous grandchild) – and C's parent reference to N'due south parent P (the previous grandparent node).

Binary tree: deleting a half leaf
Deleting a one-half leaf from a binary tree

Instance C: Deleting a Node With Two Children

How to proceed if you want to delete a node with two children?

How to delete an inner node from a binary tree?
How to delete an inner node from a binary tree?

This requires a reorganization of the binary tree. Analogous to insertion, there are once again dissimilar strategies for deletion – depending on the concrete type of binary tree. In a heap, for example, the last node of the tree is placed at the position of the deleted node and so the heap is repaired.

We utilize the following easy-to-implement variant for our tutorial:

  1. Nosotros supersede the deleted node N with its left subtree L.
  2. Nosotros suspend the right subtree R to the rightmost node of the left subtree.
Binary tree: deleting a node with two children
Deleting a node with two children from a binary tree

We tin run into clearly how this strategy leads to a severely unbalanced binary tree. Specific implementations like the binary search tree and the binary heap, therefore, take more circuitous strategies.

Deleting a Tree Node – Java Source Code

The following method (class SimpleBinaryTree starting at line 71) removes the passed node from the tree. Corresponding comments marker cases A, B, and C.

              

public void deleteNode (Node node) { if (node.parent == cypher && node != root) { throw new IllegalStateException("Node has no parent and is not root"); } // Example A: Node has no children --> set up node to null in parent if (node.left == goose egg && node.right == nada) { setParentsChild(node, nil); } // Case B: Node has one kid --> replace node by node's child in parent // Example B1: Node has merely left kid else if (node.right == cipher) { setParentsChild(node, node.left); } // Case B2: Node has only right child else if (node.left == zilch) { setParentsChild(node, node.right); } // Case C: Node has two children else { removeNodeWithTwoChildren(node); } // Remove all references from the deleted node node.parent = null; node.left = null; node.right = null; }

Code language: Java ( coffee )

The setParentsChild() method checks whether the node to be deleted is the left or right child of its parent node and replaces the corresponding reference in the parent node with the child node. kid is null if the node to be deleted has no children, and appropriately, the child reference in the parent node is set to goose egg.

In instance the deleted node is the root node, we simply replace the root reference.

              

individual void setParentsChild (Node node, Node child) { // Node is root? Has no parent, set root reference instead if (node == root) { root = kid; if (child != nil) { child.parent = null; } return; } // Am I the left or right child of my parent? if (node.parent.left == node) { node.parent.left = child; } else if (node.parent.correct == node) { node.parent.right = kid; } else { throw new IllegalStateException( "Node " + node.data + " is neither a left nor a right kid of its parent " + node.parent.information); } if (child != null) { child.parent = node.parent; } }

Code linguistic communication: Coffee ( java )

In case C (deleting a node with two children), the tree is reorganized as described in the previous section. This is done in the carve up method removeNodeWithTwoChildren():

              

private void removeNodeWithTwoChildren (Node node) { Node leftTree = node.left; Node rightTree = node.correct; setParentsChild(node, leftTree); // observe correct-most child of left tree Node rightMostChildOfLeftTree = leftTree; while (rightMostChildOfLeftTree.right != nada) { rightMostChildOfLeftTree = rightMostChildOfLeftTree.correct; } // suspend right tree to right child rightMostChildOfLeftTree.right = rightTree; rightTree.parent = rightMostChildOfLeftTree; }

Code language: Java ( java )

In the deleteSomeNodes() method of the Example1 class, you tin see how some nodes of the instance tree are deleted again.

Array Representation of a Binary Tree

Finally, I want to show you lot an alternative representation of the binary tree: storing it in an array.

The array contains as many elements every bit a perfect binary tree of the height of the binary tree to be stored, i.eastward., twoh+1-1 elements for height h (in the following paradigm: 7 elements for height 2).

The nodes of the tree are sequentially numbered from the root downwards, level past level, from left to right, and mapped to the array, as shown in the following illustration:

Array representation of a binary tree
Array representation of a binary tree

For a complete binary tree, we can trim the array appropriately – or shop the number of nodes equally an additional value.

Advantages and Disadvantages of the Array Representation

Storing a binary tree as an assortment has the following advantages:

  • Storage is more compact, as references to children (and parents, if applicative) are non required.
  • Nevertheless, you quickly get from parents to children and vice versa:
    For a node at index i,
    • the left kid is at index 2i+1,
    • the right child is at index 2i+ii,
    • the parent node is at index i/2, rounded down.
  • You can perform a level-order traversal by simply iterating over the array.

Confronting these, 1 must counterbalance the following disadvantages:

  • If the binary tree is not complete, retentivity is wasted by unused array fields.
  • If the tree grows across the array size, the data must exist copied to a new, larger assortment.
  • Equally the tree shrinks, the data should be copied (with some margin) to a new, smaller assortment to free up unused space.

Summary

In this article, you learned what a binary tree is, what types of binary trees exist, what operations you can utilize to binary trees, and how to implement a binary tree in Java.

If you lot liked the commodity, feel free to share it using one of the share buttons below. Do you want to exist informed when the next commodity is published? So click here to sign up for the HappyCoders newsletter.

kuesterreatunat.blogspot.com

Source: https://www.happycoders.eu/algorithms/binary-tree-java/

0 Response to "Do You Read Left to Right or Vice Vresa for Binary Nunmbers"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel