对List进行非固定下标的随机平均分组

对List进行非固定下标的随机平均分组

前提

项目中用到了一个调度算法,会对List中的任务平均分组到不同的集群中,之前的思路是平均取余数,然后将余数加到最后一个分片中,这样资源有很大的浪费。因为最后的余数可以加到之前的所有的分片当中,而不必是最后一个。网上有一个流传度交广的算法是将余数分配到了前几个切片中,这样在调度比较频繁的时候,前几个人集群负载会较大,造成负载不均。现在的改进是将余数随机分配到不同的分片中。

源码

  private static final Random JVM_RANDOM = new JVMRandom();

    /**
     * 将一个list均分成n个list,主要通过偏移量来实现的,改进版
     * 对分片的算法作改进,如果是10个平分成4片,则A/B会分到3片,C/D分到2片,负载会更加均衡
     * 现在改进后的remainder会随机加到平均后的分组list中
     * @param source
     * @return
     */
    public static <T> List<List<T>> average(final List<T> source, final int n) {
        if (source == null) {
            throw new NullPointerException("List must not be null");
        }
        if (n <= 0) {
            throw new IllegalArgumentException("Size must be greater than 0");
        }
        List<List<T>> result = new ArrayList<List<T>>();
        int remaider = source.size() % n; // (先计算出余数)
        int number = source.size() / n; // 然后是商
        int offset = 0;// 偏移量

        int[] idxs = Arrays.stream(buildNoRepeatIndex(n), 0, remaider).sorted().toArray();
        for (int i = 0; i < n; i++) {
            List<T> value = null;
            if (remaider > 0 && containsInts(idxs, i)) {
                value = source.subList(i * number + offset, (i + 1) * number + offset + 1);
                remaider--;
                offset++;
            } else {
                value = source.subList(i * number + offset, (i + 1) * number + offset);
            }
            result.add(value);
        }
        return result;
    }

    /**
     * 创建不重复的数组下标
     * @param source
     * @return
     */
    public static int[] buildNoRepeatIndex(int size) {
        int values[] = new int[size];
        int temp1, temp2, temp3;

        for (int i = 0; i < size; i++) {
            values[i] = i;
        }

        // 随机交换values.length次
        for (int i = 0; i < size; i++) {
            temp1 = JVM_RANDOM.nextInt(size); // 随机产生一个位置
            temp2 = JVM_RANDOM.nextInt(size); // 随机产生另一个位置

            if (temp1 != temp2) {
                temp3 = values[temp1];
                values[temp1] = values[temp2];
                values[temp2] = temp3;
            }
        }

        return values;
    }

    private static boolean containsInts(int[] array, int target) {
        for (int value : array) {
            if (value == target) {
                return true;
            }
        }
        return false;
    } 
发布了7 篇原创文章 · 获赞 13 · 访问量 3728

猜你喜欢

转载自blog.csdn.net/xiaolong7713/article/details/99298612