从JAVA + StackOverflowError中的集合项生成唯一对

时间:2015-11-13 22:44:21

标签: java arrays

如果有两个以上的数组项,我需要找到一种快速有效的方法来创建唯一对。

我的第一个问题是我提出的这个代码有时会抛出 java.lang.StackOverflowError ,为什么?我知道它会在帮助器中进行递归调用,但是如何修复呢?

我的第二个问题是如何提高代码效率。我不需要使用数组 - 它可能是其他一些集合类型。

这就是我的想法:

import java.util.HashMap;
import java.util.concurrent.ThreadLocalRandom;

/**
 * Generates unique pairs from items in array. Each item cannot occur more than
 * once as key nor value.
 *
 * @author lkallas
 */
public class UniquePairs {

    private static final String[] NAMES
            = new String[]{"Aaron", "Barney", "Charlie", "Desiré", "Edward"};

    private static final HashMap<String, String> PAIRS = new HashMap<>();

    public static void main(String[] args) {

        // Check if there is more than one item in array.
        if (NAMES.length > 1) {
            // Find pairs
            for (String name : NAMES) {
                if (!PAIRS.containsKey(name)) {
                    PAIRS.put(name, helper(name));
                }
            }
            // Show results.
            PAIRS.entrySet().stream().forEach((pair) -> {
                System.out.println(pair.getKey() + " - " + pair.getValue());
            });
        } else {
            System.out.println(NAMES[0]);

        }
    }

    /**
     * Helper for finding partner.
     *
     * @param key Name that need partner.
     * @return Unique partner.
     */
    private static String helper(String key) {

        // Get random partner from array.
        String partner = NAMES[getRandomInt(0, NAMES.length - 1)];

        // Cannot pair up a name with itself. Also partner cannot occur more than once.
        if (key.equals(partner) || PAIRS.containsValue(partner)) {
            partner = helper(key);
        }
        return partner;
    }

    /**
     * Random integer in the given range.
     *
     * @param min Minimum value of the random integer.
     * @param max Maximum value of the random integer.
     * @return Random integer in given range.
     */
    private static int getRandomInt(int min, int max) {

        return ThreadLocalRandom.current().nextInt(min, max + 1);
    }

}

修改 使用

return ThreadLocalRandom.current().nextInt(min, max + 1);

而不是

return new Random().nextInt((max - min) + 1) + min;

编辑2:

为此类操作创建了特殊类。如有必要,请随意使用。

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;

/**
 *
 * @author lkallas
 */
public class MatchMaker {

    private final Map<Object, Object> PAIRS;
    private List<? extends Object> items;

    public MatchMaker() {
        this.PAIRS = new HashMap<>();
    }

    /**
     * Pairs items uniquely and randomly so that keys nor values are repeated.
     * For proper pairing of Objects it is recommended to provide your own
     * implementation of <code>equals()</code> method. Also bear in mind that
     * you should also override <code>hashCode()</code> if there's any chance of
     * your objects being used in a hash table.
     *
     * @param input List with objects that are paired with each other.
     * @return Map with generated pairs.
     * @throws IllegalArgumentException When input List is empty or contains
     * only one item.
     */
    public Map<?, ?> getPairs(List<? extends Object> input)
            throws IllegalArgumentException {

        if (input.size() > 1) {

            items = input;

            for (int i = 0; i < input.size() - 1; i++) {
                Object k = input.get(i);
                PAIRS.put(k, getPartner(k));
            }

            Object k = items.get(items.size() - 1);
            if (PAIRS.containsValue(k)) {
                PAIRS.put(k, getPartner(k));
            } else {
                Object k1 = items.get(getRandomInt(0, items.size() - 1));
                PAIRS.put(k, PAIRS.get(k1));
                PAIRS.put(k1, k);
            }
        } else {
            throw new IllegalArgumentException("Can't pair one or less items.");
        }
        return PAIRS;
    }

    /**
     * Helper for finding a random partner.
     *
     * @param key Object that needs partner.
     * @return Unique partner that is not used by other keys.
     */
    private Object getPartner(Object key) {

        // Get random partner from array.
        Object partner = items.get(getRandomInt(0, items.size() - 1));

        // Cannot pair up a key with itself. Also partner cannot occur more than once.
        if (key.equals(partner) || PAIRS.containsValue(partner)) {
            partner = getPartner(key);
        }
        return partner;
    }

    /**
     * Random integer in the given range.
     *
     * @param min Minimum value of the random integer.
     * @param max Maximum value of the random integer.
     * @return Random integer in given range.
     */
    private static int getRandomInt(int min, int max) {

        return ThreadLocalRandom.current().nextInt(min, max + 1);
    }
}

1 个答案:

答案 0 :(得分:1)

更改此

for (String name : NAMES) {
    if (!PAIRS.containsKey(name)) {
        PAIRS.put(name, helper(name));
    }
}

for (int i = 0; i < NAMES.length - 1; i++) {
    String name = NAMES[i];
    PAIRS.put(name, helper(name));
}
String name = NAMES[NAMES.length - 1];
if (PAIRS.containsValue(name)) {
    PAIRS.put(name, helper(name));
} else {
    String otherKey = NAMES[ThreadLocalRandom.current().nextInt(0, NAMES.length - 1)];
    PAIRS.put(name, PAIRS.get(otherKey));
    PAIRS.put(otherKey, name);
}

this answer中介绍了您的版本发生了什么变化。从本质上讲,您在最后一步没有选项,因此helper会反复调用自己,直到StackOverflowError发生。