Introduction to Merkle Tree

Merkle tree also known as hash tree is a data structure used for data verification and synchronization. 
It is a tree data structure where each non-leaf node is a hash of it’s child nodes. All the leaf nodes are at the same depth and are as far left as possible. 
It maintains data integrity and uses hash functions for this purpose. 
Hash Functions: 
So before understanding how Merkle trees work, we need to understand how hash functions work. 
A hash function maps an input to a fixed output and this output is called hash. 
The output is unique for every input and this enables fingerprinting of data. 
So, huge amounts of data can be easily identified through their hash. 
 

This is a binary merkel tree, the top hash is a hash of the entire tree. 
 

  • This structure of the tree allows efficient mapping of huge data and small changes made to the data can be easily identified.
  • If we want to know where data change has occurred then we can check if data is consistent with root hash and we will not have to traverse the whole structure but only a small part of the structure.
  • The root hash is used as the fingerprint for the entire data.

For a Binary Merkel tree 
 

Operation Complexity
Space O(n)
Searching O(logn)
Traversal O(n)
Insertion O(logn)
Deletion O(logn)
Synchronization O(logn)

Applications: 
 



  • Merkle trees are useful in distributed systems where same data should exist in multiple places.
  • Merkle trees can be used to check inconsistencies.
  • Apache Cassandra uses Merkle trees to detect inconsistencies between replicas of entire databases.
  • It is used in bitcoin and blockchain.

This code is contributed by Amit Das.

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// CPP code for the above data structure
#include<bits/stdc++.h>
using namespace std;
 
/* determines the maximimum capacity of
   Hash Tree */
int maxim = 10;        
 
/* determines the number of elements
   present in Hash Tree */
int size = 0;         
 
/* node for storing an item in a Binary Tree */
struct node
{
  int key;
  int value;
  struct node *left;
  struct node *right;
};
 
/* for storing a Binary Tree at each index
   of Hash Tree */
struct bst
{
   
  /* head pointing to the root of Binary Tree */
  struct node *head;
};
 
 
 
struct bst *arr;
 
 
 
void insert_element(struct node *tree,
                          struct node *item);
 
struct node* find(struct node *tree, int key);
 
struct node* remove_element(struct node *tree,
                                     int key);
 
void display_tree(struct node *tree);
 
/* this function creates an index corresponding
   to the every given key */
int hashcode(int key)
{
  return (key % maxim);
}
 
void add(int key, int value)
{
  int index = hashcode(key);
 
  /* extracting Binary Tree at the given index */
  struct node *tree = (struct node*) arr[index].head;
   
  /* creating an item to insert in the hashTree */
  struct node *new_item = (struct node*)
                         malloc(sizeof(struct node));
 
  new_item->key = key;
  new_item->value = value;
  new_item->left = NULL;
  new_item->right = NULL;
 
  if (tree == NULL)
  {
 
    /* absence of Binary Tree at a given
       index of Hash Tree */
    cout << "Inserting " << key << " and " <<
                                 value << endl;
    arr[index].head = new_item;
    size++;
  }
 
  else
  {
 
    /* a Binary Tree is present at given index
       of Hash Tree */
    struct node *temp = find(tree, key);
 
    if (temp == NULL)
    {
 
      /*
       * Key not found in existing Binary Tree
       * Adding the key in existing Binary Tree
       */
 
      cout << "Inserting " << key << "and" <<
                                value << endl;
 
      insert_element(tree, new_item);
      size++;
    }
 
    else
    {
 
      /*
        * Key already present in existing Binary Tree
        * Updating the value of already existing key
       */
      
      temp->value = value;
    }
  }
}
 
/*
 * this function finds the given key in the Binary Tree
 * returns the node containing the key
 * returns NULL in case key is not present
 */
struct node* find(struct node *tree, int key)
{
  if (tree == NULL)
  {
    return NULL;
  }
  if (tree->key == key)
  {
    return tree;
  }
  else if (key < tree->key)
  {
    return find(tree->left, key);
  }
  else
  {
    return find(tree->right, key);
  }
}
 
/* this function inserts the newly created node
   in the existing Binary Tree */
void insert_element(struct node *tree,
                              struct node *item)
{
 
  if (item->key < tree->key)
  {
    if (tree->left == NULL)
    {
      tree->left = item;
      return;
    }
    else
    {
      insert_element(tree->left, item);
      return;
    }
  }
 
  else if (item->key > tree->key)
  {
    if (tree->right == NULL)
    {
      tree->right = item;
      return;
    }
    else
    {
      insert_element(tree->right, item);
      return;
    }
  }
}
 
/* displays the content of hash Tree */
void display()
{
  int i = 0;
  for(i = 0; i < maxim; i++)
  {
    struct node *tree = arr[i].head;
    if (tree == NULL)
    {
      cout << "arr[" << i << "] has no
                             elements" << endl;
    }
    else
    {
      cout << "arr[" << i << "] has
                             elements" << endl;
      display_tree(tree);
    }
  }
}
 
/* displays content of binary tree of
particular index */
void display_tree(struct node *tree)
{
 
  if (tree == NULL)
  {
    return;
  }
 
  cout << tree->key << " and " <<
                          tree->value << "   ";
 
  if (tree->left != NULL)
  {
    display_tree(tree->left);
  }
   
  if (tree->right != NULL)
  {
    display_tree(tree->right);
  }
}
 
/* for initializing the hash Tree */
void init()
{
  int i = 0;
  for(i = 0; i < maxim; i++)
  {
    arr[i].head = NULL;
  }
}
 
/* returns the size of hash Tree */
int size_of_hashTree()
{
  return size;
}
 
/* to del a key from hash Tree */
void del(int key)
{
  int index = hashcode(key);
  struct node *tree = (struct node*)arr[index].head;
  if (tree == NULL)
  {
    cout << key << " Key not present" << endl;
  }
 
  else
  {
    struct node *temp = find(tree, key);
    if (temp == NULL)
    {
      cout << key << " is not present";
    }
    else
    {
      tree = remove_element(tree, key);
      cout << key << " has been removed
                      form the hash tree" << endl;
    }
  }
}
 
struct node* remove_element(struct node *tree,
                                      int key)
{
 
  if (tree == NULL)
  {
    return NULL;
  }
 
  if (key < tree->key)
  {
    tree->left = remove_element(tree->left, key);
    return tree;
  }
 
  else if (key > tree->key)
  {
    tree->right = remove_element(tree->right, key);
    return tree;
  }
 
  else
  {
     
    /* reached the node */
    if (tree->left == NULL  &&  tree->right == NULL)
    {
      size--;
      return tree->left;
    }
 
    else if (tree->left != NULL  &&  tree->right == NULL)
    {
      size--;
      return tree->left;
    }
     
    else if (tree->left == NULL  &&  tree->right != NULL)
    {
      size--;
      return tree->right;
    }
 
    else
    {
      struct node *left_one = tree->left;
      while (left_one->right != NULL)
      {
        left_one = left_one->right;
      }
 
      tree->key = left_one->key;
      tree->value = left_one->value;
      tree->left = remove_element(tree->left,
                                     tree->key);
      return tree;
    }
  }
}
 
// Driver Code
int main()
{
  int choice, key, value, n, c;
  arr = (struct bst*)malloc(maxim *
                             sizeof(struct bst*));
  init();
  do
  {
    cout << "Implementation of Hash Tree" << endl;
    cout << "MENU-: \n1.Insert an item in the Hash Tree"
      "\n2.Remove an item from the Hash Tree"
      "\n3.Check the size of Hash Tree"
      "\n4.Display Hash Tree"
      "\n\n Please enter your choice-:";
     
    cin >> choice;
    switch(choice)
    {
       
      case 1:
        cout << "Inserting element in
                           Hash Tree" << endl;
        cout << "Enter key and value-:    ";
        cin >> key >> value;
        add(key, value);
        break;
         
      case 2:
        cout << "Deleting item from Hash Tree
                   \n Enter the key to delete-:";
        cin >> key;
        del(key);
        break;
         
      case 3:
        n = size_of_hashTree();
        cout << "Size of Hash Tree is-:" << n << endl;
        break;
         
      case 4:
        display();
        break;
         
      default:
        cout << "Wrong Input" << endl;
    }
    cout << "\n Do you want to continue-:
                             (press 1 for yes)     ";
    cin >> c;
 
  }while(c == 1);
  return 0;
}
 
//This code is contributed by Amit Das(amit_das)

chevron_right


 

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.




My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.



Improved By : Amit_Das