Open In App

Van Emde Boas Tree | Set 2 | Insertion, Find, Minimum and Maximum Queries

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

It is highly recommended to see previous articles on Van Emde Boas Tree first.

Procedure for Insert

  1. If no keys are present in the tree then simply assign minimum and maximum of the tree to the key.
  2. Otherwise we will go deeper in the tree and do the following:
    • If the key we want to insert is less than the current minimum of the tree, then we swap both values because the new key will be the real minimum of the tree and the key which was already at the place of the minimum will be used for the further process. 
      This concept can be thought of as lazy propagation in Van Emde Boas Tree. Because this old minimum value really is a minimum of one of the clusters of recursive Van Emde Boas Structure. So actually we don’t go deeper into the structure until the need arises. 
    • If we are not at the base case means universe size of the tree is greater than 2 then :
      • If the tree’s cluster[High(key)] is empty, then we recursively call insert over the summary and as we are doing lazy propagation, we just assign minimum and maximum value to the key and stop the recursion.
      • Otherwise, we call insert over the cluster in which the key is present.
  3. Similarly, We check for maximum and set the key as maximum if it is greater than the current maximum.

Below Image represents empty VEB(4) Tree:

VEB Tree

Now we insert 1, then it will just set the minimum and maximum of the tree to 1. You can see the Lazy propagation of 1:

VEB Tree

Now if we insert 0, then 1 will propagate to the 1st cluster and zero will be the new minimum: 

VEB

Procedure for isMember Query

  • At any point of our search, If the key is minimum or maximum of the tree, which means the key is present, then return true.
  • If we reach the base case, but above condition is false then the key must not be present in the tree so return true.
  • Otherwise recursively call the function over the cluster of the key i.e.(High(key)) and its position in the cluster i.e.(Low(key)).
  • Here we are allowing universe_size to be any power of 2, so that if the situation arises in which universe_size is less than the key value then return false.

Minimum & Maximum : Van Emde Boas Tree stores minimum and maximum as its attributes, so we can return its value if it is present and null otherwise.
 

C++




#include <bits/stdc++.h>
using namespace std;
 
class Van_Emde_Boas {
 
public:
    int universe_size;
    int minimum;
    int maximum;
    Van_Emde_Boas* summary;
    vector<Van_Emde_Boas*> clusters;
 
    // Function to return cluster numbers
    // in which key is present
    int high(int x)
    {
        int div = ceil(sqrt(universe_size));
        return x / div;
    }
 
    // Function to return position of x in cluster
    int low(int x)
    {
        int mod = ceil(sqrt(universe_size));
        return x % mod;
    }
 
    // Function to return the index from
    // cluster number and position
    int generate_index(int x, int y)
    {
        int ru = ceil(sqrt(universe_size));
        return x * ru + y;
    }
 
    // Constructor
    Van_Emde_Boas(int size)
    {
        universe_size = size;
        minimum = -1;
        maximum = -1;
 
        // Base case
        if (size <= 2) {
            summary = nullptr;
            clusters = vector<Van_Emde_Boas*>(0, nullptr);
        }
        else {
            int no_clusters = ceil(sqrt(size));
 
            // Assigning VEB(sqrt(u)) to summary
            summary = new Van_Emde_Boas(no_clusters);
 
            // Creating array of VEB Tree pointers of size sqrt(u)
            clusters = vector<Van_Emde_Boas*>(no_clusters, nullptr);
 
            // Assigning VEB(sqrt(u)) to all its clusters
            for (int i = 0; i < no_clusters; i++) {
                clusters[i] = new Van_Emde_Boas(ceil(sqrt(size)));
            }
        }
    }
};
 
// Function to return the minimum value
// from the tree if it exists
int VEB_minimum(Van_Emde_Boas* helper)
{
    return (helper->minimum == -1 ? -1 : helper->minimum);
}
 
// Function to return the maximum value
// from the tree if it exists
int VEB_maximum(Van_Emde_Boas* helper)
{
    return (helper->maximum == -1 ? -1 : helper->maximum);
}
 
// Function to insert a key in the tree
void insert(Van_Emde_Boas* helper, int key)
{
    // If no key is present in the tree
    // then set both minimum and maximum
    // to the key (Read the previous article
    // for more understanding about it)
    if (helper->minimum == -1) {
        helper->minimum = key;
        helper->maximum = key;
    }
    else {
        if (key < helper->minimum) {
 
            // If the key is less than current minimum
            // then swap it with the current minimum
            // because this minimum is actually
            // minimum of one of the internal cluster
            // so as we go deeper into the Van Emde Boas
            // we need to take that minimum to its real position
            // This concept is similar to "Lazy Propagation"
            swap(helper->minimum, key);
        }
 
        // Not base case then...
        if (helper->universe_size > 2) {
 
            // If no key is present in the cluster then insert key into
            // both cluster and summary
            if (VEB_minimum(helper->clusters[helper->high(key)]) == -1) {
                insert(helper->summary, helper->high(key));
 
                // Sets the minimum and maximum of cluster to the key
                // as no other keys are present we will stop at this level
                // we are not going deeper into the structure like
                // Lazy Propagation
                helper->clusters[helper->high(key)]->minimum = helper->low(key);
                helper->clusters[helper->high(key)]->maximum = helper->low(key);
            }
            else {
                // If there are other elements in the tree then recursively
                // go deeper into the structure to set attributes accordingly
                insert(helper->clusters[helper->high(key)], helper->low(key));
            }
        }
 
        // Sets the key as maximum it is greater than current maximum
        if (key > helper->maximum) {
            helper->maximum = key;
        }
    }
}
 
// Function that returns true if the
// key is present in the tree
bool isMember(Van_Emde_Boas* helper, int key)
{
 
    // If universe_size is less than the key
    // then we can not search the key so returns
    // false
    if (helper->universe_size < key) {
        return false;
    }
 
    // If at any point of our traversal
    // of the tree if the key is the minimum
    // or the maximum of the subtree, then
    // the key is present so returns true
    if (helper->minimum == key || helper->maximum == key) {
        return true;
    }
    else {
 
        // If after attending above condition,
        // if the size of the tree is 2 then
        // the present key must be
        // maximum or minimum of the tree if it
        // is not then it returns false because key
        // can not be present in the sub tree
        if (helper->universe_size == 2) {
            return false;
        }
        else {
 
            // Recursive call over the cluster
            // in which the key can be present
            // and also pass the new position of the key
            // i.e., low(key)
            return isMember(helper->clusters[helper->high(key)],
                            helper->low(key));
        }
    }
}
 
// Driver code
int main()
{
    Van_Emde_Boas* veb = new Van_Emde_Boas(8);
 
    // Inserting Keys
    insert(veb, 2);
    insert(veb, 3);
    insert(veb, 6);
 
    cout << boolalpha;
 
    // Checking isMember query
    cout << isMember(veb, 3) << endl;
 
    cout << isMember(veb, 4) << endl;
 
    // Maximum of VEB
    cout << VEB_maximum(veb) << endl;
 
    // Minimum of VEB
    cout << VEB_minimum(veb) << endl;
}


Java




import java.util.*;
 
class Van_Emde_Boas {
    int universe_size;
    int minimum;
    int maximum;
    Van_Emde_Boas summary;
    ArrayList<Van_Emde_Boas> clusters;
    // Function to return cluster numbers
    // in which key is present
    int high(int x)
    {
        int div = (int)Math.ceil(Math.sqrt(universe_size));
        return x / div;
    }
    // Function to return position of x in cluster
    int low(int x)
    {
        int mod = (int)Math.ceil(Math.sqrt(universe_size));
        return x % mod;
    }
    // Function to return the index from
    // cluster number and position
    int generate_index(int x, int y)
    {
        int ru = (int)Math.ceil(Math.sqrt(universe_size));
        return x * ru + y;
    }
    // Constructor
    Van_Emde_Boas(int size)
    {
        universe_size = size;
        minimum = -1;
        maximum = -1;
        // Base case
        if (size <= 2) {
            summary = null;
            clusters = new ArrayList<Van_Emde_Boas>(0);
        }
        else {
            int no_clusters
                = (int)Math.ceil(Math.sqrt(size));
            // Assigning VEB(sqrt(u)) to summary
            summary = new Van_Emde_Boas(no_clusters);
            // Creating array of VEB Tree pointers to size
            // sqrt(u)
            clusters
                = new ArrayList<Van_Emde_Boas>(no_clusters);
            // Assigning VEB(sqrt(u)) to all its clusters
            for (int i = 0; i < no_clusters; i++) {
                clusters.add(new Van_Emde_Boas(
                    (int)Math.ceil(Math.sqrt(size))));
            }
        }
    }
}
class Main {
    // Function to return the minimum value
    // from the tree if it exists
    static int VEB_minimum(Van_Emde_Boas helper)
    {
        return (helper.minimum == -1 ? -1 : helper.minimum);
    }
    // Function to return the maximum value
    // from the tree if it exists
    static int VEB_maximum(Van_Emde_Boas helper)
    {
        return (helper.maximum == -1 ? -1 : helper.maximum);
    }
    // Function to insert a key in the tree
    static void insert(Van_Emde_Boas helper, int key)
    {
        // If no key is present in the tree
        // then set both minimum and maximum
        // to the key (Read the previous article
        // for more understanding about it)
        if (helper.minimum == -1) {
            helper.minimum = key;
            helper.maximum = key;
        }
        else {
            if (key < helper.minimum) {
                // If the key is less than current minimum
                // then swap it with the current minimum
                // because this minimum is actually
                // minimum of one of the internal cluster
                // so as we go deeper into the Van Emde Boas
                // we need to take that minimum to its real
                // position This concept is similar to "Lazy
                // Propagation"
                int temp = helper.minimum;
                helper.minimum = key;
                key = temp;
            }
            // not base case then..
            if (helper.universe_size > 2) {
 
                // If no key is present in the cluster then
                // insert key into both cluster and summary
                if (VEB_minimum(helper.clusters.get(
                        helper.high(key)))
                    == -1) {
                    insert(helper.summary,
                           helper.high(key));
                    // Sets the minimum and maximum of
                    // cluster to the key
                    // as no other keys are present we will
                    // stop at this level we are not going
                    // deeper into the structure like Lazy
                    // Propagation
                    helper.clusters.get(helper.high(key))
                        .minimum
                        = helper.low(key);
                    helper.clusters.get(helper.high(key))
                        .maximum
                        = helper.low(key);
                }
                else {
                    // If there are other elements in the
                    // tree then recursively
                    // go deeper into the structure to set
                    // attributes accordingly
                    insert(helper.clusters.get(
                               helper.high(key)),
                           helper.low(key));
                }
            }
            // Sets the key as maximum it is greater than
            // current maximum
            if (key > helper.maximum) {
                helper.maximum = key;
            }
        }
    }
    // Function that returns true if the
    // key is present in the tree
    static boolean isMember(Van_Emde_Boas helper, int key)
    {
        // If universe_size is less than the key
        // then we can not search the key so returns
        // false
        if (helper.universe_size < key) {
            return false;
        }
        // If at any point of our traversal
        // of the tree if the key is the minimum
        // or the maximum of the subtree, then
        // the key is present so returns true
        if (helper.minimum == key
            || helper.maximum == key) {
            return true;
        }
        else {
            // If after attending above condition,
            // if the size of the tree is 2 then
            // the present key must be
            // maximum or minimum of the tree if it
            // is not then it returns false because key
            // can not be present in the sub tree
            if (helper.universe_size == 2) {
                return false;
            }
            else {
                // Recursive call over the cluster
                // in which the key can be present
                // and also pass the new position of the key
                // i.e., low(key)
                return isMember(
                    helper.clusters.get(helper.high(key)),
                    helper.low(key));
            }
        }
    }
    // Main Function
    public static void main(String[] args)
    {
        Van_Emde_Boas veb = new Van_Emde_Boas(8);
        // Inserting Keys
        insert(veb, 2);
        insert(veb, 3);
        insert(veb, 6);
        // Checking isMember Query
        System.out.println(
            Boolean.toString(isMember(veb, 3)));
        System.out.println(
            Boolean.toString(isMember(veb, 4)));
        // Maximum of VEB
        System.out.println(VEB_maximum(veb));
        // Minimum of VEB
        System.out.println(VEB_minimum(veb));
    }
}


Python3




import math
 
class Van_Emde_Boas:
    # Constructor
    def __init__(self, size):
        self.universe_size = size
        self.minimum = -1
        self.maximum = -1
        # Basecase
        if size <= 2:
            self.summary = None
            self.clusters = [None] * 0
        else:
            no_clusters = math.ceil(math.sqrt(size))
             
            # Assigning VEB(sqrt(u)) to summary
            self.summary = Van_Emde_Boas(no_clusters)
             
            # Creating array of VEB Tree pointers of size sqrt(u)
            # Assigning VEB(sqrt(u)) to all its clusters
            self.clusters = [Van_Emde_Boas(
                math.ceil(math.sqrt(size))) for i in range(no_clusters)]
    # Function to return cluster numbers
    # in which key is present
 
    def high(self, x):
        div = math.ceil(math.sqrt(self.universe_size))
        return x // div
    # Function to return position of x in cluster
 
    def low(self, x):
        mod = math.ceil(math.sqrt(self.universe_size))
        return x % mod
    # Function to return the index from
    #  cluster number and position
 
    def generate_index(self, x, y):
        ru = math.ceil(math.sqrt(self.universe_size))
        return x * ru + y
# Function to return the minimum value
# from the tree if it exists
 
 
def VEB_minimum(helper):
    return -1 if helper.minimum == -1 else helper.minimum
# Function to return the maximum value
# from the tree if it exists
 
 
def VEB_maximum(helper):
    return -1 if helper.maximum == -1 else helper.maximum
# Function to insert a key in the tree
 
 
def insert(helper, key):
    # If no key is present in the tree
    # then set both minimum and maximum
    # to the key (Read the previous article
    # for more understanding about it)
    if helper.minimum == -1:
        helper.minimum = key
        helper.maximum = key
    else:
        if key < helper.minimum:
            # If the key is less than current minimum
            # then swap it with the current minimum
            # because this minimum is actually
            # minimum of one of the internal cluster
            # so as we go deeper into the Van Emde Boas
            # we need to take that minimum to its real position
            # This concept is similar to "Lazy Propagation"
            helper.minimum, key = key, helper.minimum
        # Not base case then
        if helper.universe_size > 2:
            # If no key is present in the cluster then insert key into
            # both cluster and summary
            if VEB_minimum(helper.clusters[helper.high(key)]) == -1:
                insert(helper.summary, helper.high(key))
                # Sets the minimum and maximum of cluster to the key
                # as no other keys are present we will stop at this level
                # we are not going deeper into the structure like
                # Lazy Propagation
                helper.clusters[helper.high(key)].minimum = helper.low(key)
                helper.clusters[helper.high(key)].maximum = helper.low(key)
            else:
                # If there are other elements in the tree then recursively
                # go deeper into the structure to set attributes accordingly
                insert(helper.clusters[helper.high(key)], helper.low(key))
        # Sets the key as maximum it is greater than current maximum
        if key > helper.maximum:
            helper.maximum = key
 
# Function that returns true if the
# key is present in the tree
 
 
def isMember(helper, key):
    # If universe_size is less than the key
    # then we can not search the key so returns
    # false
    if helper.universe_size < key:
        return False
    # If at any point of our traversal
    # of the tree if the key is the minimum
    # or the maximum of the subtree, then
    # the key is present so returns true
    if helper.minimum == key or helper.maximum == key:
        return True
    # If after attending above condition,
    # if the size of the tree is 2 then
    # the present key must be
    # maximum or minimum of the tree if it
    # is not then it returns false because key
    # can not be present in the sub tree
    if helper.universe_size == 2:
        return False
    # Recursive call over the cluster
    # in which the key can be present
    # and also pass the new position of the key
    # i.e., low(key)
    return isMember(helper.clusters[helper.high(key)], helper.low(key))
 
 
veb = Van_Emde_Boas(8)
# Inserting keys
insert(veb, 2)
insert(veb, 3)
insert(veb, 6)
 
# Checking isMember query
print(isMember(veb, 3), end='\n')
print(isMember(veb, 4), end='\n')
 
# Maximum of VEB
print(VEB_maximum(veb), end='\n')
 
# Minimum of VEB
print(VEB_minimum(veb), end='\n')


Javascript




class Van_Emde_Boas {
  constructor(size) {
    this.universe_size = size;
    this.minimum = -1;
    this.maximum = -1;
 
    if (size <= 2) {
      this.summary = null;
      this.clusters = Array(0).fill(null);
    } else {
      const no_clusters = Math.ceil(Math.sqrt(size));
      this.summary = new Van_Emde_Boas(no_clusters);
      this.clusters = Array(no_clusters).fill(null).map(() => new Van_Emde_Boas(Math.ceil(Math.sqrt(size))));
    }
  }
 
 
    // Function to return cluster numbers
    // in which key is present
  high(x) {
    const div = Math.ceil(Math.sqrt(this.universe_size));
    return Math.floor(x / div);
  }
 
    // Function to return position of x in cluster
  low(x) {
    const mod = Math.ceil(Math.sqrt(this.universe_size));
    return x % mod;
  }
 
    // Function to return the index from
    // cluster number and position
  generate_index(x, y) {
    const ru = Math.ceil(Math.sqrt(this.universe_size));
    return x * ru + y;
  }
}
 
// Function to return the minimum value
// from the tree if it exists
function VEB_minimum(helper) {
  return helper.minimum === -1 ? -1 : helper.minimum;
}
 
// Function to return the maximum value
// from the tree if it exists
function VEB_maximum(helper) {
  return helper.maximum === -1 ? -1 : helper.maximum;
}
 
 
// Function to insert a key in the tree
function insert(helper, key) {
     
        // If no key is present in the tree
    // then set both minimum and maximum
    // to the key (Read the previous article
    // for more understanding about it)
  if (helper.minimum === -1) {
    helper.minimum = key;
    helper.maximum = key;
  } else {
       
          // If the key is less than current minimum
            // then swap it with the current minimum
            // because this minimum is actually
            // minimum of one of the internal cluster
    if (key < helper.minimum) {
      [helper.minimum, key] = [key, helper.minimum];
    }
 
    if (helper.universe_size > 2) {
         
        // If no key is present in the cluster then insert key into
            // both cluster and summary
      if (VEB_minimum(helper.clusters[helper.high(key)]) === -1) {
        insert(helper.summary, helper.high(key));
 
            // Sets the minimum and maximum of cluster to the key
            // as no other keys are present we will stop at this level
        helper.clusters[helper.high(key)].minimum = helper.low(key);
        helper.clusters[helper.high(key)].maximum = helper.low(key);
      } else {
              // If there are other elements in the tree then recursively
                // go deeper into the structure to set attributes accordingly
        insert(helper.clusters[helper.high(key)], helper.low(key));
      }
    }
     
       // Sets the key as maximum it is greater than current maximum
    if (key > helper.maximum) {
      helper.maximum = key;
}
 }}
 
// Function that returns true if the
// key is present in the tree
function isMember(helper, key) {
    // If universe_size is less than the key
// then we can not search the key so returns
// false
if (helper.universe_size < key) {
    return false;
}
 
// If at any point of our traversal
// of the tree if the key is the minimum
// or the maximum of the subtree, then
// the key is present so returns true
if (helper.minimum === key || helper.maximum === key) {
    return true;
} else {
 
    // If after attending above condition,
    // if the size of the tree is 2 then
    // the present key must be
    // maximum or minimum of the tree if it
    // is not then it returns false because key
    // can not be present in the sub tree
    if (helper.universe_size === 2) {
        return false;
    } else {
 
        // Recursive call over the cluster
        // in which the key can be present
        // and also pass the new position of the key
        // i.e., low(key)
        return isMember(helper.clusters[helper.high(key)],
                        helper.low(key));
    }
}
}
// Usage:
 
const veb = new Van_Emde_Boas(16);
// Inserting
insert(veb, 2);
insert(veb, 3);
insert(veb, 6);
 
// Checking isMember query
console.log(isMember(veb, 3));
console.log(isMember(veb, 4));
 
// Maximum of VEB
console.log( VEB_maximum(veb));
 
// Minimum if VEB
console.log(VEB_minimum(veb));


C#




using System;
using System.Collections.Generic;
 
public class Van_Emde_Boas {
 
    public int universe_size;
    public int minimum;
    public int maximum;
    public Van_Emde_Boas summary;
    public List<Van_Emde_Boas> clusters;
 
    public Van_Emde_Boas(int size)
    {
        universe_size = size;
        minimum = -1;
        maximum = -1;
 
        // Base case
        if (size <= 2) {
            summary = null;
            clusters = new List<Van_Emde_Boas>(0);
        }
        else {
            int no_clusters
                = (int)Math.Ceiling(Math.Sqrt(size));
            summary = new Van_Emde_Boas(no_clusters);
 
            clusters
                = new List<Van_Emde_Boas>(no_clusters);
 
            for (int i = 0; i < no_clusters; i++) {
                clusters.Add(new Van_Emde_Boas(
                    (int)Math.Ceiling(Math.Sqrt(size))));
            }
        }
    }
 
    // Function to return cluster numbers
    // in which key is present
    public int high(int x)
    {
        int div = (int)Math.Ceiling(Math.Sqrt(universe_size));
        return x / div;
    }
    // Function to return position of x in cluster
    public int low(int x)
    {
        int mod = (int)Math.Ceiling(Math.Sqrt(universe_size));
        return x % mod;
    }
 
    // Function to return position of x in cluster
    public int generate_index(int x, int y)
    {
        int ru = (int)Math.Ceiling(Math.Sqrt(universe_size));
        return x * ru + y;
    }
}
 
public class Main_Program {
 
 
    // Function to return the minimum value
    // from the tree if it exists
    public static int VEB_minimum(Van_Emde_Boas helper)
    {
        return (helper.minimum == -1 ? -1 : helper.minimum);
    }
 
    // Function to return the maximum value
    // from the tree if it exists
    public static int VEB_maximum(Van_Emde_Boas helper)
    {
        return (helper.maximum == -1 ? -1 : helper.maximum);
    }
 
 
    // Function to insert a key in the tree
    static void insert(Van_Emde_Boas helper, int key)
    {
         
    // If no key is present in the tree
        // then set both minimum and maximum
        // to the key (Read the previous article
        // for more understanding about it)
        if (helper.minimum == -1) {
            helper.minimum = key;
            helper.maximum = key;
        }
        else {
 
    // If the key is less than the current minimum
            // then swap it with the current minimum
            // because this minimum is actually
            // minimum of one of the internal cluster
            if (key < helper.minimum) {
                int temp = helper.minimum;
                helper.minimum = key;
                key = temp;
            }
 
            // Not base case then...
            if (helper.universe_size > 2) {
 
 
                // If no key is present in the cluster then
                // insert key into both cluster and summary
                if (VEB_minimum(helper.clusters[helper.high(key)])
                    == -1) {
                    insert(helper.summary,
                        helper.high(key));
 
                    // Sets the minimum and maximum of
                    // cluster to the key as no other keys
                    // are present we will stop at this
                    // level
                    helper.clusters[helper.high(key)]
                        .minimum
                        = helper.low(key);
                    helper.clusters[helper.high(key)]
                        .maximum
                        = helper.low(key);
                }
                else {
 
                    // If there are other elements in the
                    // tree then recursively go deeper into
                    // the structure to set attributes
                    // accordingly
                    insert(helper.clusters[
                            helper.high(key)],
                        helper.low(key));
                }
            }
// Sets the key as maximum it is greater than
            // current maximum
            if (key > helper.maximum) {
                helper.maximum = key;
            }
        }
    }
        // Function that returns true if the
    // key is present in the tree
public static bool isMember(Van_Emde_Boas helper, int key)
{
    if (helper.universe_size < key)
    {
        return false;
    }
    if (helper.minimum == key || helper.maximum == key)
    {
        return true;
    }
    else
    {
            // If after attending above condition,if the
            // size of the tree is 2 then the present key
            // must be maximum or minimum of the tree
        if (helper.universe_size == 2)
        {
            return false;
        }
        else
        {
            return isMember(helper.clusters[helper.high(key)], helper.low(key));
        }
    }
}
 
        // Driver code
    public static void Main() {
        Van_Emde_Boas veb = new Van_Emde_Boas(8);
         
        // Inserting
        insert(veb, 2);
        insert(veb, 3);
        insert(veb, 6);
       
         // Checking isMember query
        Console.WriteLine(isMember(veb,3));
        Console.WriteLine(isMember(veb,4));
         
        // Maximum ov VEB
        Console.WriteLine(VEB_maximum(veb));
         
        // Minimum of VEB
        Console.WriteLine(VEB_minimum(veb));
    }
}


Output: 

true
false
6
2

 



Last Updated : 26 Mar, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads