diff --git a/src/mhtree/InternalNode.java b/src/mhtree/InternalNode.java
index 060a681f580aa0ff853d403f160ddb083e03bbfe..e409850ec626ba07ebc1fb25f145540ac896fe49 100644
--- a/src/mhtree/InternalNode.java
+++ b/src/mhtree/InternalNode.java
@@ -4,10 +4,13 @@ import cz.muni.fi.disa.similarityoperators.cover.AbstractRepresentation.Precompu
 import messif.objects.LocalAbstractObject;
 
 import java.io.Serializable;
-import java.util.*;
-import java.util.function.Function;
+import java.util.Collection;
+import java.util.List;
 import java.util.stream.Collectors;
 
+/**
+ * Represents internal node of MH-Tree, i.e. a non-leaf node.
+ */
 public class InternalNode extends Node implements Serializable {
 
     /**
@@ -15,52 +18,116 @@ public class InternalNode extends Node implements Serializable {
      */
     private static final long serialVersionUID = 2L;
 
-    private final Set<Node> children;
+    /**
+     * List of children.
+     */
+    private final List<Node> children;
 
-    InternalNode(PrecomputedDistances distances, InsertType insertType, ObjectToNodeDistance objectToNodeDistance) {
+    InternalNode(PrecomputedDistances distances, InsertType insertType, ObjectToNodeDistance objectToNodeDistance, List<Node> children) {
         super(distances, insertType, objectToNodeDistance);
-        children = new HashSet<>();
-    }
 
-    public void addChildren(List<Node> children) {
-        this.children.addAll(children);
+        this.children = children;
     }
 
-    public Set<Node> getChildren() {
+    /**
+     * Returns the list of child nodes.
+     *
+     * @return the list of child nodes
+     */
+    List<Node> getChildren() {
         return children;
     }
 
-    public Node getNearestChild(LocalAbstractObject object) {
-        Map<Node, Double> nodeToObjectDistance = children.stream()
-                .collect(Collectors.toMap(Function.identity(), node -> node.getDistance(object)));
+    /**
+     * Returns the nearest child to the {@code object}.
+     *
+     * @param object object to which the distance is measured
+     * @return the nearest child to the {@code object}
+     */
+    Node getNearestChild(LocalAbstractObject object) {
+        Node nearestChild = children.get(0);
+        double minDistance = nearestChild.getDistance(object);
 
-        return Collections.min(nodeToObjectDistance.entrySet(), Map.Entry.comparingByValue()).getKey();
+        for (Node child : children) {
+            double distance = child.getDistance(object);
+
+            if (distance < minDistance) {
+                minDistance = distance;
+                nearestChild = child;
+            }
+        }
+
+        return nearestChild;
     }
 
-    public void addObject(LocalAbstractObject object) {
-        addNewObject(object);
+    /**
+     * Adds {@code object} into this node.
+     *
+     * @param object object to be added
+     */
+    void addObject(LocalAbstractObject object) {
+        addObjectIntoHull(object);
     }
 
-    public Set<LocalAbstractObject> getObjects() {
-        return children.stream()
+    /**
+     * Returns the list of objects stored in node's descendants.
+     *
+     * @return the list of objects stored in node's descendants
+     */
+    List<LocalAbstractObject> getObjects() {
+        return children
+                .stream()
                 .map(Node::getObjects)
                 .flatMap(Collection::stream)
-                .collect(Collectors.toSet());
+                .collect(Collectors.toList());
     }
 
-    public int getHeight() {
-        return children.stream()
+    /**
+     * Returns the height of this node.
+     *
+     * @return the height of this node
+     */
+    int getHeight() {
+        return children
+                .stream()
                 .mapToInt(Node::getHeight)
                 .summaryStatistics()
                 .getMax() + 1;
     }
 
-    public List<Node> getNodesOnLevel(int level) {
-        if (getLevel() == level) return Collections.singletonList(this);
+    /**
+     * Adds this node and this node's descendants into {@code nodes}.
+     *
+     * @param nodes list of nodes, where gathered nodes are added
+     */
+    void gatherNodes(List<Node> nodes) {
+        nodes.add(this);
+        nodes.addAll(children);
+    }
 
-        return children.stream()
-                .map(child -> child.getNodesOnLevel(level))
+    /**
+     * Returns a list of leaf nodes under this node.
+     *
+     * @return a list of leaf node under this node
+     */
+    List<LeafNode> getLeafNodes() {
+        return children
+                .stream()
+                .map(Node::getLeafNodes)
                 .flatMap(Collection::stream)
                 .collect(Collectors.toList());
     }
+
+    /**
+     * Returns the number of internal nodes in this subtree.
+     *
+     * @return the number of internal nodes in this subtree
+     */
+    int getInternalNodesCount() {
+        return children
+                .stream()
+                .filter(Node::isInternal)
+                .mapToInt(x -> ((InternalNode) x).getInternalNodesCount())
+                .sum() + 1;
+    }
 }