首先,您应该使用泛型集合:
Map<Integer, List<Integer>> map = new LinkedHashMap<Integer, List<Integer>>();
由于这看起来像家庭作业,因此我尝试提供提示以帮助您前进,而不是完整的解决方案。StackOverflow 不应该为你写作业:-)
您需要交换两个元素的键。一旦你有了它,你只需要获取与给定键对应的值并在两个键之间交换它们。然后添加随机密钥生成 - 改进 @Eyal 的通用解决方案:
class MapSwapper1 {
private static Random rnd = new Random();
private static K[] nullArray = new K[0];
public static <K,V> void swapTwoRandomValues(Map<K,V> map){
if (map.size() <= 1)
throw new IllegalArgumentException("Not enough items");
//Choose 2 random positions pos1<pos2
int pos1 = 0, pos2 = 0;
while (pos1 == pos2) {
pos1 = rnd.nextInt(map.size());
pos2 = rnd.nextInt(map.size());
}
// Get the keys into an indexable array
K[] keys = map.keySet().toArray(nullArray);
swap(map, keys[pos1], keys[pos2]);
}
private static void <K,V> swap(Map<K, V> map, K key1, K key2) {
V tmp = map.get(key1);
map.put(key1, map.get(key2));
map.put(key2, tmp);
}
}
我认为这个解决方案可能比他的更快。但是,如果您在同一个映射中多次交换值而不更改映射(即没有在映射中添加、删除或更改键),您可以通过keys
在后续交换调用之间重用数组来进一步优化解决方案:
class MapSwapper2<K, V> {
private Random rnd = new Random();
private Map<K,V> map;
private K[] keys;
public MapSwapper2(Map<K, V> map) {
resetKeys();
this.map = map;
}
public void resetKeys() {
if (map.size() <= 1)
throw new IllegalArgumentException("Not enough items");
keys = map.keySet().toArray(new K[0]);
}
public void swapTwoRandomValues() {
if (map.size() != keys.length)
resetKeys();
//Choose 2 random positions pos1<pos2
int pos1 = 0, pos2 = 0;
while (pos1 == pos2) {
pos1 = rnd.nextInt(map.size());
pos2 = rnd.nextInt(map.size());
}
swap(map, keys[pos1], keys[pos2]);
}
private void swap(K key1, K key2) {
V tmp = map.get(key1);
map.put(key1, map.get(key2));
map.put(key2, tmp);
}
}
如您所见,MapSwapper2
对象与特定的地图实例相关联,它们可以重复交换其元素。resetKeys
如果映射键已更改,则应调用该方法。交换器可以检测映射的大小是否已更改,但不能检测例如已删除键并添加了另一个键。