@Override
    @SuppressWarnings("unchecked")
    public Neighbor<double[], E>[] search(double[] q, int k) {
        if (k < 1) {
            throw new IllegalArgumentException("Invalid k: " + k);
        }

        Set<Integer> candidates = getCandidates(q);
        k = Math.min(k, candidates.size());

        HeapSelect<Neighbor<double[], E>> heap = new HeapSelect<>(new Neighbor[k]);

        for (int index : candidates) {
            double[] key = keys.get(index);
            if (q != key) {
                double distance = MathEx.distance(q, key);
                heap.add(new Neighbor<>(key, data.get(index), index, distance));
            }
        }
        
        heap.sort();
        return heap.toArray();
    }
@Test
    public void testRange() {
        System.out.println("range");

        int[] recall = new int[testx.length];
        for (int i = 0; i < testx.length; i++) {
            ArrayList<Neighbor<double[], double[]>> n1 = new ArrayList<>();
            ArrayList<Neighbor<double[], double[]>> n2 = new ArrayList<>();
            lsh.search(testx[i], 8.0, n1);
            naive.search(testx[i], 8.0, n2);

            for (Neighbor m2 : n2) {
                for (Neighbor m1 : n1) {
                    if (m1.index == m2.index) {
                        recall[i]++;
                        break;
                    }
                }
            }
        }

        System.out.format("q1     of recall is %d%n", MathEx.q1(recall));
        System.out.format("median of recall is %d%n", MathEx.median(recall));
        System.out.format("q3     of recall is %d%n", MathEx.q3(recall));
    }