示例#1
0
 private Node insert(Node root, String data, int pos) {
   if (pos == data.length()) {
     return root;
   }
   if (root == null) {
     root = new Node();
     root.data = data.charAt(pos);
     root.eq = insert(root.eq, data, pos + 1);
     if (pos == (data.length() - 1)) {
       root.isLeaf = true;
     }
   } else {
     if (root.data == data.charAt(pos)) {
       root.eq = insert(root.eq, data, pos + 1);
       if (pos == (data.length() - 1)) {
         root.isLeaf = true;
       }
     } else if (root.data < data.charAt(pos)) {
       root.right = insert(root.right, data, pos);
     } else {
       root.left = insert(root.left, data, pos);
     }
   }
   return root;
 }
示例#2
0
文件: C45.java 项目: alei76/tctm
 public void print(String prefix) {
   if (isLeaf()) {
     int bestLabelIndex = getGainRatio().getBaseLabelDistribution().getBestIndex();
     int numMajorityLabel =
         (int) (getGainRatio().getBaseLabelDistribution().value(bestLabelIndex) * getSize());
     System.out.println(
         "root:"
             + getGainRatio().getBaseLabelDistribution().getBestLabel()
             + " "
             + numMajorityLabel
             + "/"
             + getSize());
   } else {
     String featName = m_dataDict.lookupObject(getGainRatio().getMaxValuedIndex()).toString();
     double threshold = getGainRatio().getMaxValuedThreshold();
     System.out.print(prefix + "\"" + featName + "\" <= " + threshold + ":");
     if (m_leftChild.isLeaf()) {
       int bestLabelIndex = m_leftChild.getGainRatio().getBaseLabelDistribution().getBestIndex();
       int numMajorityLabel =
           (int)
               (m_leftChild.getGainRatio().getBaseLabelDistribution().value(bestLabelIndex)
                   * m_leftChild.getSize());
       System.out.println(
           m_leftChild.getGainRatio().getBaseLabelDistribution().getBestLabel()
               + " "
               + numMajorityLabel
               + "/"
               + m_leftChild.getSize());
     } else {
       System.out.println();
       m_leftChild.print(prefix + "|    ");
     }
     System.out.print(prefix + "\"" + featName + "\" > " + threshold + ":");
     if (m_rightChild.isLeaf()) {
       int bestLabelIndex =
           m_rightChild.getGainRatio().getBaseLabelDistribution().getBestIndex();
       int numMajorityLabel =
           (int)
               (m_rightChild.getGainRatio().getBaseLabelDistribution().value(bestLabelIndex)
                   * m_rightChild.getSize());
       System.out.println(
           m_rightChild.getGainRatio().getBaseLabelDistribution().getBestLabel()
               + " "
               + numMajorityLabel
               + "/"
               + m_rightChild.getSize());
     } else {
       System.out.println();
       m_rightChild.print(prefix + "|    ");
     }
   }
 }
示例#3
0
  public static void printPaths(Node node, ArrayList<Integer> path) {
    if (node == null) {
      return;
    }

    ArrayList<Integer> newPath = (ArrayList<Integer>) path.clone();
    newPath.add(Integer.valueOf(node.data));

    if (node.isLeaf()) {
      printPath(newPath);
      return;
    }

    printPaths(node.left, newPath);
    printPaths(node.right, newPath);

    /* The following alternate approach won't work
       * because we'll append a node to the same list every time,
       * even when we move back up the tree and start on a new branch.
       *
       * path.add(Integer.valueOf(node.data));

       if (node.isLeaf()) {
       	printPath(path);
       	return;
       }

       printPaths(node.left , path);
    printPaths(node.right, path);
    */
  }
 private void recursiveGetNodes(
     Node node, Shape shape, int detailLevel, boolean inclParents, Collection<Node> result) {
   if (node.isLeaf()) { // cell is within shape
     result.add(node);
     return;
   }
   final Collection<Node> subCells = node.getSubCells(shape);
   if (node.getLevel() == detailLevel - 1) {
     if (subCells.size() < node.getSubCellsSize()) {
       if (inclParents) result.add(node);
       for (Node subCell : subCells) {
         subCell.setLeaf();
       }
       result.addAll(subCells);
     } else { // a bottom level (i.e. detail level) optimization where all boxes intersect, so use
       // parent cell.
       node.setLeaf();
       result.add(node);
     }
   } else {
     if (inclParents) {
       result.add(node);
     }
     for (Node subCell : subCells) {
       recursiveGetNodes(subCell, shape, detailLevel, inclParents, result); // tail call
     }
   }
 }
  MultiTypeNode copyFromFlatNode(Node node) {

    MultiTypeNode mNode = new MultiTypeNode();

    mNode.height = node.height;
    mNode.parent = node.parent;

    mNode.nTypeChanges = 0;
    mNode.changeTimes.addAll(new ArrayList<Double>());
    mNode.changeTypes.addAll(new ArrayList<Integer>());
    mNode.nodeType = 0;

    mNode.labelNr = node.labelNr;

    if (node.isLeaf()) {

      int type = (int) node.getMetaData("location");

      if (type != 0) {

        mNode.setNodeType(type);
        mNode.addChange(
            0,
            (node.getHeight()
                + (node.getParent().getHeight() - node.getHeight()) * Randomizer.nextDouble()));
      }

    } else {

      mNode.addChild(copyFromFlatNode(node.getLeft()));
      mNode.addChild(copyFromFlatNode(node.getRight()));
    }

    return mNode;
  }
示例#6
0
 /**
  * Iteratively traverses a tree from the specified node in a post-order fashion, performing
  * computations at each node.
  *
  * @param node The node the traversal starts from.
  * @param pv The population vector to use for node computations.
  */
 public void iterativeTraverse(Node root, PopulationVector pv) {
   Stack<Node> s = new Stack<Node>();
   s.push(root);
   Node prev = null;
   while (!s.empty()) {
     Node curr = s.peek();
     if (prev == null || prev.leftChild() == curr || prev.rightChild() == curr) {
       if (curr.leftChild() != null) s.push(curr.leftChild());
       else if (curr.rightChild() != null) s.push(curr.rightChild());
       // If traversing up tree from left, traverse to right child if available.
     } else if (curr.leftChild() == prev && curr.rightChild() != null) {
       s.push(curr.rightChild());
     }
     // Otherwise traversing up tree from right, compute g arrays and pop.
     else {
       if (curr.isLeaf()) {
         initLeafNode(curr, pv);
       } else {
         computeSubnetNode(curr, pv);
       }
       s.pop();
     }
     prev = curr;
   }
 }
示例#7
0
  /**
   * Performs modifications, and reassigns certain properties on the tree in place. The input is
   * assumed to be a properly "crunched" tree. This is mainly to aid creating the "mini-tree" for
   * the data selection in the RDF mapping. <br>
   * The only properties that are recalculated are the weights and the selectors.
   */
  public void recrunch(Node node) {
    if (!node.isLeaf()) {
      for (Node child : node.getChildren()) {
        recrunch(child);
      }

      computeWeightAndSelector(node);
    }
  }
示例#8
0
 // make a lookup table from symbols and their encodings
 private void buildCode(String[] code, Node n, String path) {
   // If n isn't a leaf, we need to go deeper
   if (!n.isLeaf()) {
     buildCode(code, n.left, path + '0');
     buildCode(code, n.right, path + '1');
   } else // if it's a leaf, we fill the case in the code table that correspond to this letter with
          // the equivalent code that represent it
   {
     code[n.c] = path;
   }
 }
示例#9
0
  public int predict(Message msg) {
    Node current = root;
    while (!current.isLeaf()) { // if not null must have two children
      if (msg.contains(current.getWord())) {
        current = current.getLeft();
      } else {
        current = current.getRight();
      }
    }

    return current.getClassification();
  }
 /** Will add the trailing leaf byte for leaves. This isn't particularly efficient. */
 public static List<String> nodesToTokenStrings(Collection<Node> nodes) {
   List<String> tokens = new ArrayList<String>((nodes.size()));
   for (Node node : nodes) {
     final String token = node.getTokenString();
     if (node.isLeaf()) {
       tokens.add(token + (char) Node.LEAF_BYTE);
     } else {
       tokens.add(token);
     }
   }
   return tokens;
 }
示例#11
0
 /**
  * Recursively searches the tree for all intersecting entries. Immediately calls execute() on the
  * passed IntProcedure when a matching entry is found.
  *
  * <p>[x] TODO rewrite this to be non-recursive? Make sure it doesn't slow it down.
  */
 private void intersects(Rectangle r, IntProcedure v, Node n) {
   for (int i = 0; i < n.entryCount; i++) {
     if (r.intersects(n.entries[i])) {
       if (n.isLeaf()) {
         v.execute(n.ids[i]);
       } else {
         Node childNode = getNode(n.ids[i]);
         intersects(r, v, childNode);
       }
     }
   }
 }
示例#12
0
 private void intersects(float x1, float y1, float x2, float y2, IntProcedure v, Node n) {
   for (int i = 0; i < n.entryCount; i++) {
     if (intersects(x1, y1, x2, y2, n.entries[i])) {
       if (n.isLeaf()) {
         v.execute(n.ids[i]);
       } else {
         Node childNode = getNode(n.ids[i]);
         intersects(x1, y1, x2, y2, v, childNode);
       }
     }
   }
 }
示例#13
0
 private void writeCode(Node n) throws IOException {
   if (n.isLeaf()) {
     output.write(1);
     System.out.print(1);
     output.write((int) n.c);
     System.out.print((int) n.c);
   } else {
     output.write(0);
     System.out.print(0);
     writeCode(n.left);
     writeCode(n.right);
   }
 }
示例#14
0
  /** @see com.infomatiq.jsi.SpatialIndex#contains(Rectangle, IntProcedure) */
  public void contains(Rectangle r, IntProcedure v) {
    // find all rectangles in the tree that are contained by the passed
    // rectangle
    // written to be non-recursive (should model other searches on this?)

    parents.clear();
    parents.push(rootNodeId);

    parentsEntry.clear();
    parentsEntry.push(-1);

    // TODO: possible shortcut here - could test for intersection with the
    // MBR of the root node. If no intersection, return immediately.

    while (parents.size() > 0) {
      Node n = getNode(parents.peek());
      int startIndex = parentsEntry.peek() + 1;

      if (!n.isLeaf()) {
        // go through every entry in the index node to check
        // if it intersects the passed rectangle. If so, it
        // could contain entries that are contained.
        boolean intersects = false;
        for (int i = startIndex; i < n.entryCount; i++) {
          if (r.intersects(n.entries[i])) {
            parents.push(n.ids[i]);
            parentsEntry.pop();
            parentsEntry.push(i); // this becomes the start index
            // when the child has been
            // searched
            parentsEntry.push(-1);
            intersects = true;
            break; // ie go to next iteration of while()
          }
        }
        if (intersects) {
          continue;
        }
      } else {
        // go through every entry in the leaf to check if
        // it is contained by the passed rectangle
        for (int i = 0; i < n.entryCount; i++) {
          if (r.contains(n.entries[i])) {
            v.execute(n.ids[i]);
          }
        }
      }
      parents.pop();
      parentsEntry.pop();
    }
  }
示例#15
0
  /**
   * Recursively traverses a tree from the specified node in a post-order fashion, performing
   * computations at each node.
   *
   * @param node The node the traversal starts from.
   * @param pv The population vector to use for node computations.
   */
  public void recursiveTraverse(Node node, PopulationVector pv) {
    if (node.leftChild() != null) {
      recursiveTraverse(node.leftChild(), pv);
    }
    if (node.rightChild() != null) {
      recursiveTraverse(node.rightChild(), pv);
    }

    if (node.isLeaf()) {
      initLeafNode(node, pv);
    } else {
      computeSubnetNode(node, pv);
    }
  }
  /**
   * get clade for internal node
   *
   * @param idGroup order of labels
   * @param internalNode Node
   * @param boolean[] clade
   */
  public static void getClade(IdGroup idGroup, Node internalNode, boolean[] clade) {
    if (internalNode.isLeaf() || internalNode.isRoot()) {
      throw new IllegalArgumentException("Only internal nodes (and no root) nodes allowed");
    }

    // make sure clade is reset
    for (int i = 0; i < clade.length; i++) {
      clade[i] = false;
    }

    // mark all leafs downstream of the node
    // AJD removed loop, as doesn't appear to be necessary
    SplitUtils.markNode(idGroup, internalNode, clade);
  }
  /**
   * Assign a category to an item. This is the implementation of algorithm 4.1 on page 53 of the
   * book.
   *
   * @param item The Item which has to be classified by the algorithm.
   * @return A String describing the name of category to which the item belongs.
   */
  public String assignCategory(Item item) {
    Node current;

    // 1)	start at the root node
    current = root;
    // 2)	repeat while the current node is not a leaf
    while (!current.isLeaf()) {
      //    a)	follow the arc corresponding to the item's
      //              value of the current node split attribute
      //    b)	the node reached becomes the current node
      current = current.follow(item.getFeatureValue(current.getLabel()));
    }
    // 3)	the label of the leaf node is the class of the item
    return current.getLabel();
  }
示例#18
0
    private void addTreeItem(JSONObject jsonObject, int index) {

      Node node =
          new Node(
              jsonObject.get("id").isString().stringValue(),
              jsonObject.get("leaf").isBoolean().booleanValue(),
              jsonObject.get("text").isString().stringValue());
      if (node.getText() != null) {
        TreeItem item = new TreeItem();
        item.setText(node.getText());
        item.setUserObject(node);
        if (!node.isLeaf()) item.addItem(""); // Temporarily add an item so we can expand this node

        treeItem.addItem(item);
      }
    }
  static void markNode(IdGroup idGroup, Node node, boolean[] split) {
    if (node.isLeaf()) {
      String name = node.getIdentifier().getName();
      int index = idGroup.whichIdNumber(name);

      if (index < 0) {
        throw new IllegalArgumentException("INCOMPATIBLE IDENTIFIER (" + name + ")");
      }

      split[index] = true;
    } else {
      for (int i = 0; i < node.getChildCount(); i++) {
        markNode(idGroup, node.getChild(i), split);
      }
    }
  }
示例#20
0
  private void print(Stack<Node> stack, Node n) {
    if (n.isLeaf()) {
      assert n.value != null;
      for (Node node : stack) {
        System.out.print(node.key + "->");
      }
      System.out.print(n.value);
      System.out.println();

      return;
    }
    for (Map.Entry<Character, Node> e : n.children.entrySet()) {
      stack.push(e.getValue());
      print(stack, e.getValue());
      stack.pop();
    }
  }
示例#21
0
 /**
  * Recursively searches the tree for the nearest entry. Other queries call execute() on an
  * IntProcedure when a matching entry is found; however nearest() must store the entry Ids as it
  * searches the tree, in case a nearer entry is found. Uses the member variable nearestIds to
  * store the nearest entry IDs.
  *
  * <p>[x] TODO rewrite this to be non-recursive?
  */
 private float nearest(Point p, Node n, float nearestDistance) {
   for (int i = 0; i < n.entryCount; i++) {
     float tempDistance = n.entries[i].distance(p);
     if (n.isLeaf()) { // for leaves, the distance is an actual nearest distance
       if (tempDistance < nearestDistance) {
         nearestDistance = tempDistance;
         nearestIds.clear();
       }
       if (tempDistance <= nearestDistance) {
         nearestIds.add(n.ids[i]);
       }
     } else { // for index nodes, only go into them if they potentially could have
       // a rectangle nearer than actualNearest
       if (tempDistance <= nearestDistance) {
         // search the child node
         nearestDistance = nearest(p, getNode(n.ids[i]), nearestDistance);
       }
     }
   }
   return nearestDistance;
 }
示例#22
0
  private Node makeCrunchNode(Node topologicalNode) {
    // copy the intrinsic properties: id, weights, relationship, and selectors will be set
    Node node = new Node(topologicalNode);
    // assign the id from the name hash
    node.setId(computeId(node));
    if (!topologicalNode.isLeaf()) {
      List<Node> newChildren = new ArrayList<Node>();
      List<Node> children = topologicalNode.getChildren();
      for (Node child : children) {
        // depth-first traversal
        Node newChild = makeCrunchNode(child);
        // set the child-parent relationship
        newChildren.add(newChild);
        newChild.setParent(node);
      }
      node.setChildren(newChildren);

      // weights and selector should be set after all lower nodes are crunched
      computeWeightAndSelector(node);
    }
    return node;
  }
示例#23
0
  /**
   * Remove the node if possible or set its count to 0 if it has children and it needs to be kept
   * around
   */
  private Node tryRemove(Node node) {
    if (node == null) {
      return null;
    }

    if (node.weightedCount >= ZERO_WEIGHT_THRESHOLD) {
      --nonZeroNodeCount;
    }

    weightedCount -= node.weightedCount;

    Node result = null;
    if (node.isLeaf()) {
      --totalNodeCount;
    } else if (node.hasSingleChild()) {
      result = node.getSingleChild();
      --totalNodeCount;
    } else {
      node.weightedCount = 0;
      result = node;
    }

    return result;
  }
  /**
   * get split for branch associated with internal node
   *
   * @param idGroup order of labels
   * @param internalNode Node
   * @param boolean[] split
   */
  public static void getSplit(IdGroup idGroup, Node internalNode, boolean[] split) {
    if (internalNode.isLeaf() || internalNode.isRoot()) {
      throw new IllegalArgumentException("Only internal nodes (and no root) nodes allowed");
    }

    // make sure split is reset
    for (int i = 0; i < split.length; i++) {
      split[i] = false;
    }

    // mark all leafs downstream of the node

    for (int i = 0; i < internalNode.getChildCount(); i++) {
      markNode(idGroup, internalNode, split);
    }

    // standardize split (i.e. first index is alway true)
    if (split[0] == false) {
      for (int i = 0; i < split.length; i++) {
        if (split[i] == false) split[i] = true;
        else split[i] = false;
      }
    }
  }
示例#25
0
  /**
   * Removes an element from the tree.
   *
   * @param val The value.
   */
  public void remove(int val) {

    Node k = findNode(root, val);
    if (k == null)
      throw new IllegalArgumentException(
          "Cannot remove " + val + " because such a node does not exist.");
    Node kParent = k.parent;

    System.out.printf("Removing value: %d%n", val);

    // Delete node that is a leaf.
    if (k.isLeaf()) {

      System.out.println(" -> Corresponding node is a leaf : Performing cutoff.");

      if (k == root) root = null;
      else k.parent.removeSon(k);

      // Delete node that us a single son.
    } else if (k.isSingleSon()) {

      System.out.println(
          " -> Corresponding node has only one son. Connecting node's son and parent.");

      if (k == root) k.onlySon().setRoot();
      else k.parent.replace(k, k.onlySon());

      // Delete inner node.
    } else {

      // Check if it is more efficient to exchange node by another left or right side node
      // If uncertain, choose right side (and thus bigger element) for finding a replacement.
      boolean replaceByLeft = k.left != null && (k.right == null || k.left.height > k.right.height);

      Node s;
      if (replaceByLeft) s = findNextSmallerNode(k);
      else s = findNextBiggerNode(k);

      System.out.printf(
          " -> Correspondig node has two sons. Removing next %s element from tree first"
              + " before proceeding. Removing: %d%n",
          replaceByLeft ? "bigger" : "smaller", s.value);

      // Remove node first that is to be used as a replacement.
      remove(s.value);

      System.out.printf(" -> %d is removed. Proceeding with replacing %d%n", s.value, k.value);

      // Set new node in place of the removed node.
      if (k == root) s.setRoot();
      else k.parent.replace(k, s);

      // Fix father - son relationships.
      s.setLeft(k.left);
      s.setRight(k.right);

      s.update();
    }

    if (kParent != null) up(kParent);
  }
示例#26
0
  public void outputToJSON(String filePath, int numTopWords, double boundaryFactor) {
    System.out.println("Writing down the model...");

    JSONObject featureCollection = new JSONObject();
    featureCollection.put("type", "FeatureCollection");

    JSONArray features = new JSONArray();
    Queue<Node> nodeQueue = new LinkedList<>();
    nodeQueue.offer(root);
    while (!nodeQueue.isEmpty()) {
      Node currentNode = nodeQueue.poll();
      JSONObject feature = new JSONObject();
      feature.put("type", "Feature");
      feature.put("id", currentNode.hashCode());

      JSONObject properties = new JSONObject();
      properties.put("level", currentNode.level + 1);
      properties.put("num_documents", currentNode.numCustomers);

      if (currentNode.parent != null) {
        properties.put("parent", currentNode.parent.hashCode());
      }

      if (!currentNode.isLeaf()) {
        JSONArray children = new JSONArray();
        for (Node child : currentNode.children) {
          children.put(child.hashCode());
        }
        properties.put("children", children);
      }

      JSONArray center = new JSONArray();
      double longitude = currentNode.location.longitude;
      center.put(longitude);
      double latitude = currentNode.location.latitude;
      center.put(latitude);
      properties.put("center", center);

      JSONArray deviation = new JSONArray();
      double longitudeDeviation = Math.sqrt(currentNode.location.longitudeVariance);
      deviation.put(longitudeDeviation);
      double latitudeDeviation = Math.sqrt(currentNode.location.latitudeVariance);
      deviation.put(latitudeDeviation);
      properties.put("deviation", deviation);

      JSONArray topWords = new JSONArray();
      PriorityQueue<Map.Entry<Integer, Integer>> wordMinHeap =
          new PriorityQueue<>(
              numTopWords,
              new Comparator<Map.Entry<Integer, Integer>>() {
                @Override
                public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
                  return o1.getValue() - o2.getValue();
                }
              });
      for (Map.Entry<Integer, Integer> entry : currentNode.wordCounts.entrySet()) {
        if (wordMinHeap.size() < numTopWords) {
          wordMinHeap.offer(entry);
        } else {
          if (entry.getValue() > wordMinHeap.peek().getValue()) {
            wordMinHeap.poll();
            wordMinHeap.offer(entry);
          }
        }
      }
      while (!wordMinHeap.isEmpty()) {
        topWords.put(this.id2Word.get(wordMinHeap.poll().getKey()));
      }
      properties.put("top_words", topWords);

      feature.put("properties", properties);

      JSONObject geometry = new JSONObject();
      geometry.put("type", "Polygon");

      JSONArray coordinates = new JSONArray();
      JSONArray boundary = new JSONArray();
      double east = longitude + boundaryFactor * longitudeDeviation;
      double west = longitude - boundaryFactor * longitudeDeviation;
      double north = latitude + boundaryFactor * latitudeDeviation;
      double south = latitude - boundaryFactor * latitudeDeviation;
      boundary.put(new JSONArray(new double[] {west, north}));
      boundary.put(new JSONArray(new double[] {east, north}));
      boundary.put(new JSONArray(new double[] {east, south}));
      boundary.put(new JSONArray(new double[] {west, south}));
      boundary.put(new JSONArray(new double[] {west, north}));
      coordinates.put(boundary);
      geometry.put("coordinates", coordinates);

      feature.put("geometry", geometry);

      features.put(feature);

      for (Node child : currentNode.children) {
        nodeQueue.offer(child);
      }
    }

    featureCollection.put("features", features);

    try {
      PrintWriter writer = new PrintWriter(filePath);
      featureCollection.write(writer);
      writer.close();
    } catch (FileNotFoundException e) {
      System.err.println("Model JSON cannot be created.");
    }
  }
示例#27
0
  /** @see com.infomatiq.jsi.SpatialIndex#delete(Rectangle, int) */
  public boolean delete(Rectangle r, int id) {
    // FindLeaf algorithm inlined here. Note the "official" algorithm
    // searches all overlapping entries. This seems inefficient to me,
    // as an entry is only worth searching if it contains (NOT overlaps)
    // the rectangle we are searching for.
    //
    // Also the algorithm has been changed so that it is not recursive.

    // FL1 [Search subtrees] If root is not a leaf, check each entry
    // to determine if it contains r. For each entry found, invoke
    // findLeaf on the node pointed to by the entry, until r is found or
    // all entries have been checked.
    parents.clear();
    parents.push(rootNodeId);

    parentsEntry.clear();
    parentsEntry.push(-1);
    Node n = null;
    int foundIndex = -1; // index of entry to be deleted in leaf

    while (foundIndex == -1 && parents.size() > 0) {
      n = getNode(parents.peek());
      int startIndex = parentsEntry.peek() + 1;

      if (!n.isLeaf()) {
        deleteLog.debug("searching node " + n.nodeId + ", from index " + startIndex);
        boolean contains = false;
        for (int i = startIndex; i < n.entryCount; i++) {
          if (n.entries[i].contains(r)) {
            parents.push(n.ids[i]);
            parentsEntry.pop();
            parentsEntry.push(i); // this becomes the start index when the child has been searched
            parentsEntry.push(-1);
            contains = true;
            break; // ie go to next iteration of while()
          }
        }
        if (contains) {
          continue;
        }
      } else {
        foundIndex = n.findEntry(r, id);
      }

      parents.pop();
      parentsEntry.pop();
    } // while not found

    if (foundIndex != -1) {
      n.deleteEntry(foundIndex, minNodeEntries);
      condenseTree(n);
      size--;
    }

    // shrink the tree if possible (i.e. if root node has exactly one entry,and that
    // entry is not a leaf node, delete the root (it's entry becomes the new root)
    Node root = getNode(rootNodeId);
    while (root.entryCount == 1 && treeHeight > 1) {
      root.entryCount = 0;
      rootNodeId = root.ids[0];
      treeHeight--;
      root = getNode(rootNodeId);
    }

    return (foundIndex != -1);
  }