Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java如何根据值将树映射划分为两个相等的映射_Java_Sorting_Maps_Treemap - Fatal编程技术网

Java如何根据值将树映射划分为两个相等的映射

Java如何根据值将树映射划分为两个相等的映射,java,sorting,maps,treemap,Java,Sorting,Maps,Treemap,好的,我有一个树形图,它包含playerID和一个playerAverageScore。我想把它分成另外两张地图,这样每支球队的球员数量相等,球员的总得分大致相同(偏差约+/-2) private TreeMap teamScoreMap=new TreeMap(); 私有树映射team1=新树映射(); 私有TreeMap team2=新TreeMap(); 公共团队() { teamScoreMap.put(001,5.0); teamScoreMap.put(002,8.4); teamS

好的,我有一个树形图,它包含playerID和一个playerAverageScore。我想把它分成另外两张地图,这样每支球队的球员数量相等,球员的总得分大致相同(偏差约+/-2)

private TreeMap teamScoreMap=new TreeMap();
私有树映射team1=新树映射();
私有TreeMap team2=新TreeMap();
公共团队()
{
teamScoreMap.put(001,5.0);
teamScoreMap.put(002,8.4);
teamScoreMap.put(003,2.1);
teamScoreMap.put(004,6.5);
teamScoreMap.put(005,4.5);
teamScoreMap.put(006,3.2);
teamScoreMap.put(007,9.8);
teamScoreMap.put(008,7.6);
} 
试试这个

TreeMap<Integer,Double> teamScoreMap = new TreeMap<Integer, Integer>(bigMap);
int size = teamScoreMap.size();
SortedMap<Integer, Double> team1 = teamScoreMap .subMap(0, size/2);
SortedMap<Integer, Double> team2 = teamScoreMap .subMap((size/2)+1,size);
TreeMap teamScoreMap=新的TreeMap(bigMap);
int size=teamScoreMap.size();
SortedMap team1=teamScoreMap.subMap(0,大小/2);
SortedMap team2=teamScoreMap.subMap((大小/2)+1,大小);

没有理由实际强制转换到树映射,因为它没有提供比SortedMap更多的功能。

逻辑就在那里,您只需要完成将每个团队添加到每个映射的代码

让所有可能的团队,将他们的平均值与之前的最佳平均值进行比较。如果差异低于上一个,则交换它们

最后,你会得到两者之间最好的区别


输出示例
公共类测试{
私有映射tsm=newtreemap();
私有映射team1=新树映射();
私有映射组2=新树映射();
公共服务小组(){
双平均值=tsm.值()
.stream()
.mapToDouble(x->x)
.average()
.getAsDouble();
int[]最佳团队=新int[4];
双倍最佳平均值=10;
双tmp;
对于(int i=1;i,显示了计算此特定情况的最佳结果的一种方法。更一般而言,您试图解决的是的一个特殊实例,并且存在相关问题-例如

基本上没有找到最优解的有效方法

计算最优解的蛮力方法是计算一半元素的所有可能选择,计算它们的和,并找到与期望和偏差最小的和

然而,在许多情况下,人们对最佳解决方案不感兴趣,而只对“好”的解决方案感兴趣。这可以通过贪婪的方法实现:首先,按降序排列分数。然后,浏览团队成员列表,并将他们中的每一个分配给当前分数较低的团队

这两种方法均在此处实施,例如:

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.TreeMap;


public class MapSplit
{
    public static void main(String[] args)
    {
        TreeMap<Integer, Double> teamScoreMap = new TreeMap<Integer, Double>();
        teamScoreMap.put(1, 5.0);
        teamScoreMap.put(2, 8.4);
        teamScoreMap.put(3, 2.1);
        teamScoreMap.put(4, 6.5);
        teamScoreMap.put(5, 4.5);
        teamScoreMap.put(6, 3.2);
        teamScoreMap.put(7, 9.8);
        teamScoreMap.put(8, 7.6);

        solveOptimal(teamScoreMap);
        solveGreedy(teamScoreMap);
    }

    private static void solveOptimal(Map<Integer, Double> teamScoreMap)
    {
        List<Entry<Integer, Double>> entries = 
            new ArrayList<Entry<Integer, Double>>(
                teamScoreMap.entrySet());

        double totalSum = computeSum(entries);
        ChoiceIterable<Entry<Integer, Double>> ci = 
            new ChoiceIterable<Entry<Integer, Double>>(
                teamScoreMap.size() / 2, entries);

        List<Entry<Integer, Double>> bestTeam = null;
        double minError = Double.POSITIVE_INFINITY;
        for (List<Entry<Integer, Double>> team : ci)
        {
            double teamSum = computeSum(team);
            double error = Math.abs(teamSum - totalSum * 0.5);
            if (error < minError)
            {
                bestTeam = team;
                minError = error;
            }
        }

        Set<Entry<Integer, Double>> teamA = 
            new LinkedHashSet<Entry<Integer, Double>>(bestTeam);
        Set<Entry<Integer, Double>> teamB = 
            new LinkedHashSet<Entry<Integer, Double>>(
                teamScoreMap.entrySet());
        teamB.removeAll(teamA);

        System.out.println("Optimal result:");
        printResult(teamA, teamB);
    }

    private static void solveGreedy(Map<Integer, Double> teamScoreMap)
    {
        List<Entry<Integer, Double>> entries = 
            new ArrayList<Entry<Integer, Double>>(
                teamScoreMap.entrySet());
        Collections.sort(entries, (e0, e1) -> 
            Double.compare(e1.getValue(), e0.getValue()));

        Set<Entry<Integer, Double>> teamA = 
            new LinkedHashSet<Entry<Integer, Double>>();
        double sumA = 0;
        Set<Entry<Integer, Double>> teamB = 
            new LinkedHashSet<Entry<Integer, Double>>();
        double sumB = 0;

        for (Entry<Integer, Double> entry : entries)
        {
            if (sumA < sumB)
            {
                teamA.add(entry);
                sumA += entry.getValue();
            }
            else
            {
                teamB.add(entry);
                sumB += entry.getValue();
            }
        }

        System.out.println("Greedy result:");
        printResult(teamA, teamB);
    }

    private static void printResult(
        Collection<Entry<Integer, Double>> teamA, 
        Collection<Entry<Integer, Double>> teamB)
    {
        System.out.println("Team A:");
        for (Entry<Integer, Double> entry : teamA)
        {
            System.out.println("  " + entry);
        }
        System.out.println("Sum: " + computeSum(teamA));

        System.out.println("Team B:");
        for (Entry<Integer, Double> entry : teamB)
        {
            System.out.println("  " + entry);
        }
        System.out.println("Sum: " + computeSum(teamB));
    }

    private static double computeSum(
        Collection<Entry<Integer, Double>> entries)
    {
        return entries.stream().map(
            e -> e.getValue()).reduce(0.0, (a,b) -> a+b);
    }


}

// From https://github.com/javagl/Combinatorics/blob/master/src/main/
// java/de/javagl/utils/math/combinatorics/CombinationIterable.java
class ChoiceIterable<T> implements Iterable<List<T>>
{
    private final List<T> input;
    private final int sampleSize;
    private final long numElements;
    public ChoiceIterable(int sampleSize, List<T> input)
    {
        this.sampleSize = sampleSize;
        this.input = input;
        BigInteger nf = factorial(input.size());
        BigInteger kf = factorial(sampleSize);
        BigInteger nmkf = factorial(input.size() - sampleSize);
        BigInteger divisor = kf.multiply(nmkf);
        BigInteger result = nf.divide(divisor);
        numElements = result.longValue();    
    }

    public static BigInteger factorial(int n)
    {
        BigInteger f = BigInteger.ONE;
        for (int i = 2; i <= n; i++)
        {
            f = f.multiply(BigInteger.valueOf(i));
        }
        return f;
}     
    @Override
    public Iterator<List<T>> iterator()
    {
        return new Iterator<List<T>>()
        {
            private int current = 0;
            private final int chosen[] = new int[sampleSize];
            // Initialization of first choice
            {
                for (int i = 0; i < sampleSize; i++)
                {
                    chosen[i] = i;
                }
            }

            @Override
            public boolean hasNext()
            {
                return current < numElements;
            }

            @Override
            public List<T> next()
            {
                if (!hasNext())
                {
                    throw new NoSuchElementException("No more elements");
                }

                List<T> result = new ArrayList<T>(sampleSize);
                for (int i = 0; i < sampleSize; i++)
                {
                    result.add(input.get(chosen[i]));
                }
                current++;
                if (current < numElements)
                {
                    increase(sampleSize - 1, input.size() - 1);
                }
                return result;
            }

            private void increase(int n, int max)
            {
                if (chosen[n] < max)
                {
                    chosen[n]++;
                    for (int i = n + 1; i < sampleSize; i++)
                    {
                        chosen[i] = chosen[i - 1] + 1;
                    }
                }
                else
                {
                    increase(n - 1, max - 1);
                }
            }

            @Override
            public void remove()
            {
                throw new UnsupportedOperationException(
                    "May not remove elements from a choice");
            }
        };
    }
}

显示贪婪结果不是最佳结果,但在这种情况下仍然相当不错。

顺便说一句,不要在整数文本前加零前缀,除非你真的想用八进制指定它们。是的,我知道我一直这样做,我不知道为什么,我以前在我的代码中已经纠正了这一点,所以这里的关键是播放器编号和value是他们的分数吗?如果你每队只有8名球员,有
2^8
方法将他们分配到2个队(其中一些方法导致一个队没有球员;其中一些是其他分配的“镜像”)。
2^7
如果你总是将第一名球员分配到
(这也消除了“镜像”).尽管如此,只需评估“质量”在这些少量的作业中,选择最好的。你不一定能控制偏差。如果你只有两名球员,一名得分为1,另一名得分为10,会怎么样?谢谢,这将分为两张地图,但我需要两张地图中的总值大致相同。请查看此图,同时这可能会给出正确的答案第二个最佳答案在这种情况下,它的伸缩性不是很好。从实现的角度来看,因为你不能轻易地将它扩展到每个团队超过4名球员。从算法的角度来看,因为它将具有指数复杂性。@Marco13我同意,但这回答了OP目前的具体问题,我认为这对n来说是可以的哦。我没有足够的数学技能来执行更好的/可伸缩的/通用的代码。当然,无意冒犯-我只是想提一下,这样OP就不会试图将此应用于一个包含100个条目的映射,并且循环变量用完;-)@Marco13没问题,谢谢你在这两方面的评论:)。当然,我觉得你的解决方案在解决一般问题方面更好。
{false=[1=5.0, 4=6.5, 5=4.5, 8=7.6], true=[2=8.4, 3=2.1, 6=3.2, 7=9.8]}
// false = 23.6 in total             true = 23.5 in total
// As you see, the difference between both is the minimum possible (0.1)
public class Test {
    private Map<Integer, Double> tsm = new TreeMap<>();
    private Map<Integer, Double> team1 = new TreeMap<>();
    private Map<Integer, Double> team2 = new TreeMap<>();

    public void splitTeams() {
        double average = tsm.values()
                            .stream()
                            .mapToDouble(x->x)
                            .average()
                            .getAsDouble();
        int[] bestTeam = new int[4];
        double bestAverage = 10;
        double tmp;

        for (int i = 1 ; i <= 8 ; i++) {
            for (int j = 1 ; j <= 8 ; j++) {
                for (int k = 1 ; k <= 8 ; k++) {
                    for (int l = 1 ; l <= 8 ; l++) {
                        if (Stream.of(i, j, k, l).distinct().count() == 4) {
                            tmp = Stream.of(tsm.get(i), tsm.get(j), tsm.get(k), tsm.get(l))
                                        .mapToDouble(x -> x)
                                        .average()
                                        .getAsDouble();
                            if (Math.abs(average - tmp) < bestAverage) {
                                bestTeam[0] = i;
                                bestTeam[1] = j;
                                bestTeam[2] = k;
                                bestTeam[3] = l;
                                bestAverage = Math.abs(average - tmp);
                            }
                        }
                    }
                }
            }
        }

        List<Integer> team1 = Arrays.stream(bestTeam).boxed().collect(Collectors.toList());
        Map<Boolean, List<Entry<Integer, Double>>> both = tsm.entrySet()
                                                             .stream()
                                                             .collect(Collectors.partitioningBy(e -> team1.contains(e.getKey())));
        System.out.println(both);
    }

    public void createTeam() {
        tsm.put(1, 5.0);
        tsm.put(2, 8.4);
        tsm.put(3, 2.1);
        tsm.put(4, 6.5);
        tsm.put(5, 4.5);
        tsm.put(6, 3.2);
        tsm.put(7, 9.8);
        tsm.put(8, 7.6);
    }

    public static void main(String[] args) {
        Test t = new Test();
        t.createTeam();
        t.splitTeams();
        System.out.println();
    }
}
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.TreeMap;


public class MapSplit
{
    public static void main(String[] args)
    {
        TreeMap<Integer, Double> teamScoreMap = new TreeMap<Integer, Double>();
        teamScoreMap.put(1, 5.0);
        teamScoreMap.put(2, 8.4);
        teamScoreMap.put(3, 2.1);
        teamScoreMap.put(4, 6.5);
        teamScoreMap.put(5, 4.5);
        teamScoreMap.put(6, 3.2);
        teamScoreMap.put(7, 9.8);
        teamScoreMap.put(8, 7.6);

        solveOptimal(teamScoreMap);
        solveGreedy(teamScoreMap);
    }

    private static void solveOptimal(Map<Integer, Double> teamScoreMap)
    {
        List<Entry<Integer, Double>> entries = 
            new ArrayList<Entry<Integer, Double>>(
                teamScoreMap.entrySet());

        double totalSum = computeSum(entries);
        ChoiceIterable<Entry<Integer, Double>> ci = 
            new ChoiceIterable<Entry<Integer, Double>>(
                teamScoreMap.size() / 2, entries);

        List<Entry<Integer, Double>> bestTeam = null;
        double minError = Double.POSITIVE_INFINITY;
        for (List<Entry<Integer, Double>> team : ci)
        {
            double teamSum = computeSum(team);
            double error = Math.abs(teamSum - totalSum * 0.5);
            if (error < minError)
            {
                bestTeam = team;
                minError = error;
            }
        }

        Set<Entry<Integer, Double>> teamA = 
            new LinkedHashSet<Entry<Integer, Double>>(bestTeam);
        Set<Entry<Integer, Double>> teamB = 
            new LinkedHashSet<Entry<Integer, Double>>(
                teamScoreMap.entrySet());
        teamB.removeAll(teamA);

        System.out.println("Optimal result:");
        printResult(teamA, teamB);
    }

    private static void solveGreedy(Map<Integer, Double> teamScoreMap)
    {
        List<Entry<Integer, Double>> entries = 
            new ArrayList<Entry<Integer, Double>>(
                teamScoreMap.entrySet());
        Collections.sort(entries, (e0, e1) -> 
            Double.compare(e1.getValue(), e0.getValue()));

        Set<Entry<Integer, Double>> teamA = 
            new LinkedHashSet<Entry<Integer, Double>>();
        double sumA = 0;
        Set<Entry<Integer, Double>> teamB = 
            new LinkedHashSet<Entry<Integer, Double>>();
        double sumB = 0;

        for (Entry<Integer, Double> entry : entries)
        {
            if (sumA < sumB)
            {
                teamA.add(entry);
                sumA += entry.getValue();
            }
            else
            {
                teamB.add(entry);
                sumB += entry.getValue();
            }
        }

        System.out.println("Greedy result:");
        printResult(teamA, teamB);
    }

    private static void printResult(
        Collection<Entry<Integer, Double>> teamA, 
        Collection<Entry<Integer, Double>> teamB)
    {
        System.out.println("Team A:");
        for (Entry<Integer, Double> entry : teamA)
        {
            System.out.println("  " + entry);
        }
        System.out.println("Sum: " + computeSum(teamA));

        System.out.println("Team B:");
        for (Entry<Integer, Double> entry : teamB)
        {
            System.out.println("  " + entry);
        }
        System.out.println("Sum: " + computeSum(teamB));
    }

    private static double computeSum(
        Collection<Entry<Integer, Double>> entries)
    {
        return entries.stream().map(
            e -> e.getValue()).reduce(0.0, (a,b) -> a+b);
    }


}

// From https://github.com/javagl/Combinatorics/blob/master/src/main/
// java/de/javagl/utils/math/combinatorics/CombinationIterable.java
class ChoiceIterable<T> implements Iterable<List<T>>
{
    private final List<T> input;
    private final int sampleSize;
    private final long numElements;
    public ChoiceIterable(int sampleSize, List<T> input)
    {
        this.sampleSize = sampleSize;
        this.input = input;
        BigInteger nf = factorial(input.size());
        BigInteger kf = factorial(sampleSize);
        BigInteger nmkf = factorial(input.size() - sampleSize);
        BigInteger divisor = kf.multiply(nmkf);
        BigInteger result = nf.divide(divisor);
        numElements = result.longValue();    
    }

    public static BigInteger factorial(int n)
    {
        BigInteger f = BigInteger.ONE;
        for (int i = 2; i <= n; i++)
        {
            f = f.multiply(BigInteger.valueOf(i));
        }
        return f;
}     
    @Override
    public Iterator<List<T>> iterator()
    {
        return new Iterator<List<T>>()
        {
            private int current = 0;
            private final int chosen[] = new int[sampleSize];
            // Initialization of first choice
            {
                for (int i = 0; i < sampleSize; i++)
                {
                    chosen[i] = i;
                }
            }

            @Override
            public boolean hasNext()
            {
                return current < numElements;
            }

            @Override
            public List<T> next()
            {
                if (!hasNext())
                {
                    throw new NoSuchElementException("No more elements");
                }

                List<T> result = new ArrayList<T>(sampleSize);
                for (int i = 0; i < sampleSize; i++)
                {
                    result.add(input.get(chosen[i]));
                }
                current++;
                if (current < numElements)
                {
                    increase(sampleSize - 1, input.size() - 1);
                }
                return result;
            }

            private void increase(int n, int max)
            {
                if (chosen[n] < max)
                {
                    chosen[n]++;
                    for (int i = n + 1; i < sampleSize; i++)
                    {
                        chosen[i] = chosen[i - 1] + 1;
                    }
                }
                else
                {
                    increase(n - 1, max - 1);
                }
            }

            @Override
            public void remove()
            {
                throw new UnsupportedOperationException(
                    "May not remove elements from a choice");
            }
        };
    }
}
Optimal result:
Team A:
  1=5.0
  4=6.5
  5=4.5
  8=7.6
Sum: 23.6
Team B:
  2=8.4
  3=2.1
  6=3.2
  7=9.8
Sum: 23.5
Greedy result:
Team A:
  2=8.4
  8=7.6
  1=5.0
  3=2.1
Sum: 23.1
Team B:
  7=9.8
  4=6.5
  5=4.5
  6=3.2
Sum: 24.0