function createBinaryTree(distance, items, indices) {
  var N = indices.length;

  var PointerArray = getPointerArray(N);

  var C = 0,
      nodes = new PointerArray(N),
      lefts = new PointerArray(N),
      rights = new PointerArray(N),
      mus = new Float64Array(N),
      stack = [0, 0, N],
      distances = new Float64Array(N),
      nodeIndex,
      vantagePoint,
      medianIndex,
      lo,
      hi,
      mid,
      mu,
      i,
      l;

  while (stack.length) {
    hi = stack.pop();
    lo = stack.pop();
    nodeIndex = stack.pop();

    // Getting our vantage point
    vantagePoint = indices[hi - 1];
    hi--;

    l = hi - lo;

    // Storing vantage point
    nodes[nodeIndex] = vantagePoint;

    // We are in a leaf
    if (l === 0)
      continue;

    // We only have two elements, the second one has to go right
    if (l === 1) {

      // We put remaining item to the right
      mu = distance(items[vantagePoint], items[indices[lo]]);

      mus[nodeIndex] = mu;

      // Right
      C++;
      rights[nodeIndex] = C;
      nodes[C] = indices[lo];

      continue;
    }

    // Computing distance from vantage point to other points
    for (i = lo; i < hi; i++)
      distances[indices[i]] = distance(items[vantagePoint], items[indices[i]]);

    inplaceQuickSortIndices(distances, indices, lo, hi);

    // Finding median of distances
    medianIndex = lo + (l / 2) - 1;

    // Need to interpolate?
    if (medianIndex === (medianIndex | 0)) {
      mu = (
        distances[indices[medianIndex]] +
        distances[indices[medianIndex + 1]]
      ) / 2;
    }
    else {
      mu = distances[indices[Math.ceil(medianIndex)]];
    }

    // Storing mu
    mus[nodeIndex] = mu;

    mid = lowerBoundIndices(distances, indices, mu, lo, hi);

    // console.log('Vantage point', items[vantagePoint], vantagePoint);
    // console.log('mu =', mu);
    // console.log('lo =', lo);
    // console.log('hi =', hi);
    // console.log('mid =', mid);

    // console.log('need to split', Array.from(indices).slice(lo, hi).map(i => {
    //   return [distances[i], distance(items[vantagePoint], items[i]), items[i]];
    // }));

    // Right
    if (hi - mid > 0) {
      C++;
      rights[nodeIndex] = C;
      stack.push(C, mid, hi);
      // console.log('Went right with ', Array.from(indices).slice(mid, hi).map(i => {
      //   return [distances[i], distance(items[vantagePoint], items[i]), items[i]];
      // }));
    }

    // Left
    if (mid - lo > 0) {
      C++;
      lefts[nodeIndex] = C;
      stack.push(C, lo, mid);
      // console.log('Went left with', Array.from(indices).slice(lo, mid).map(i => {
      //   return [distances[i], distance(items[vantagePoint], items[i]), items[i]];
      // }));
    }

    // console.log();
  }

  return {
    nodes: nodes,
    lefts: lefts,
    rights: rights,
    mus: mus
  };
}
Function used to create the binary tree.

@param  {function}     distance - Distance function to use.
@param  {array}        items    - Items to index (will be mutated).
@param  {array}        indices  - Indexes of the items.
@return {Float64Array}          - The flat binary tree.