package presenter.algorithms.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

/**
 * Created by armin on 29.06.17.
 */
public class FastElementSelector {

    /**
     * @param a
     * @param i
     * @return
     */
    public static Double randomizedSelect(List<Double> a, double i) {
        int start = 0;
        int end = a.size() - 1;

        if (i >= end + 1) {
            return a.get(end);
        }

        while (true) {
            if (start >= end) {
                return a.get(start);
            }
            int q = randomizedPartition(a, start, end);
            int k = q - start + 1;

            if (i == k) {
                return a.get(q);
            } else {
                if (i < k) {
                    end = q - 1;
                } else {
                    start = q + 1;
                    i = i - k;
                }
            }
        }
    }

    /**
     * @param a
     * @param start
     * @param end
     * @return
     */
    private static int randomizedPartition(List<Double> a, int start, int end) {
        int i = 0;
        Random random = new Random(System.currentTimeMillis());

        //alternative:  ThreadLocalRandom.current()
        if (start < end) {
            i = start + random.nextInt(end - start);
        } else {
            i = end + random.nextInt(start - end);
        }

        Collections.swap(a, end, i);
        return partition(a, start, end);
    }

    /**
     * @param a
     * @param start
     * @param end
     * @return
     */
    private static int partition(List<Double> a, int start, int end) {
        Double x = a.get(end);
        int i = start - 1;
        for (int j = start; j <= end - 1; j++) {
            if (a.get(j) <= x) {
                i++;
                Collections.swap(a, i, j);
            }
        }
        Collections.swap(a, i + 1, end);
        return i + 1;
    }
}
