All Downloads are FREE. Search and download functionalities are using the official Maven repository.

shz.core.alg.search.TopK Maven / Gradle / Ivy

There is a newer version: 2024.0.2
Show newest version
package shz.core.alg.search;

import static shz.core.ArrayHelp.swap;

public final class TopK {
    private TopK() {
        throw new IllegalStateException();
    }

    /**
     * bfprt查找第k小值
     * 时间复杂度 O(n)
     */
    public static int bfprt(int[] a, int k) {
        if (k <= 1) {
            int min = 0;
            for (int i = 1; i < a.length; ++i) if (a[i] < a[min]) min = i;
            return a[min];
        }
        return bfprt(a, 0, a.length - 1, k);
    }

    private static int bfprt(int[] a, int lo, int hi, int k) {
        if (lo == hi) return a[lo];

        int lt = -1, i = lo, gt = hi;
        //这里选取中位数为快排的基准值
        int v = median(a, lo, hi);
        //标记指针 i 是否第一次遇到 v
        boolean mark = false;
        while (i <= gt) {
            if (a[i] < v) {
                if (mark) swap(a, lt++, i);
                ++i;
            } else if (a[i] > v) swap(a, i, gt--);
            else {
                if (!mark) {
                    mark = true;
                    //初始lt
                    lt = i;
                }
                ++i;
            }
        }

        //a[lo...lt-1] < v = a[lt...gt] < a[gt+1...hi]
        if (lo + k - 1 >= lt) {
            if (lo + k - 1 <= gt) return a[lt];
            return bfprt(a, gt + 1, hi, k + lo - gt - 1);
        }
        return bfprt(a, lo, lt - 1, k);
    }

    private static int median(int[] a, int lo, int hi) {
        int n = hi - lo + 1;
        int[] medians = new int[n / 5 + (n % 5 == 0 ? 0 : 1)];
        int i = 0, j = lo + 4;
        for (; j < hi; j += 5) medians[i++] = mid(a, j - 4, j);
        medians[i] = mid(a, j - 4, hi);
        //获取中位数的中位数
        return bfprt(medians, 0, medians.length - 1, medians.length / 2);
    }

    /**
     * 取中位数
     */
    private static int mid(int[] a, int lo, int hi) {
        //插入排序
        int min = lo;
        for (int i = lo + 1; i <= hi; ++i) if (a[i] < a[min]) min = i;
        swap(a, lo, min);
        for (int i = lo + 2; i <= hi; ++i) for (int j = i; a[j] < a[j - 1]; --j) swap(a, j, j - 1);
        return a[lo + (hi - lo) / 2];
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy