2014-08-31 43 views
1

我想在形式Map创建Java中的地图是需要的地图整数随机

0 -> 1 
2 -> 0 
1 -> 2 

或者

0 -> 4 
1 -> 0 
2 -> 2 
3 -> 3 
4 -> 1 

每INT应该准确地映射到不同的INT在范围中。 我想通过功能的int地图的大小,并取回一个Map对象。 实现此功能的好方法是什么?

+1

使数组0..N,然后洗牌,然后把地图从0到N的顺序。好吧,如果大小从一开始就知道。 – 2014-08-31 15:04:57

+1

'实现这个功能的最有效的方法是不使用Java.'为什么? – Dici 2014-08-31 15:09:51

+0

没理由。垃圾邮件。 – 2014-08-31 15:10:36

回答

2
public static Map<Integer,Integer> bijectiveMap(int n) { 
     List<Integer> values = new ArrayList<>(n); 
     for (int i=0 ; i<n ; i++) 
      values.add(i); 
     Collections.shuffle(values); 

     Map<Integer,Integer> result = new HashMap<>(); 
     for (int i=0 ; i<n ; i++) 
      result.put(i,values.get(i)); 
     return result; 
    } 

输出对于n = 10:

{0=7, 1=5, 2=3, 3=6, 4=1, 5=4, 6=2, 7=8, 8=9, 9=0}

1

洗牌可能会做。可能不是最快的,但肯定是最干净的方式。

public Map<Integer, Integer> getRandomMapping(int min, int max){ 
    List<Integer> arr = new ArrayList<Integer>(); 
    //Fill array in order 
    for(int i = 0; i < max + 1; i++){ 
     arr.add(i + min); 
    } 
    //Shuffle 
    Collections.shuffle(arr); 

    //Read into map 
    Map<Integer, Integer> m = new HashMap<Integer, Integer>(); 
    for(int i = 0; i < max + 1; i++){ 
     m.put(new Integer(i + min), arr.get(i)); 
    } 

    return m; 
} 
1

忘记Map。只是洗牌的Array/ArrayList(与a[i] = i初始化)。分配质量取决于您的洗牌算法。

+0

+1,数组/ ArrayList更容易使用。如果由于某种原因确实需要返回一个'Map',你可以创建一个包装数组并实现'Map'接口的类。 – 2014-08-31 15:40:19

0

如果避免Collections.shuffle。这里

public static Map<Integer, Integer> foo(final int size) { 
    final Map<Integer, Integer> out = new HashMap<Integer, Integer>(size*5); 
    final List<Integer> values = new ArrayList<Integer>(size); 
    Random r = new Random(); 
    for (int i = 0; i < size; i++) { 
     values.add(i, i); 
    } 
    for (int i = size; i > 0; i--) { 
     out.put(new Integer(i), values.remove(r.nextInt(i))); 
    } 
    return out; 
} 
  1. 创建适当大小的所有集合(HashMap的负载因子这里是20%左右,它会吃太多空间)。在一个循环
  2. 作为的keySet
  3. 洗牌,并添加元素没有顺序也没有必要从1到去到N
  4. 一放就乱瞬态静态的,那么它也将是更快的在某些情况下。
  5. 为int和长期使用Apache的集合,而不是整数包装器

    final static transient Random r = new Random(); 
    final public static Map<Integer, Integer> foo(final int size) { 
        final Map<Integer, Integer> out = new HashMap<Integer, Integer>(size*5); 
        final List<Integer> values = new ArrayList<Integer>(size); 
        int i; 
    
        for (i = 0; i < size; i++) { 
         values.add(i, i); 
        } 
        for (; i > 0; i--) { 
         out.put(new Integer(i), values.remove(r.nextInt(i))); 
        } 
        return out; 
    } 
    

我的列表道歉循环,这是太多的std ::今天载体。快速的解决方案

final static transient Random rand = new Random(); 
final public static Map<Integer, Integer> foo(final int size) { 
    final Map<Integer, Integer> out = new HashMap<Integer, Integer>(size*5); 
    final Integer[] values = new Integer[size]; 
    int i, r; 
    for (i = 0; i <size; i++) { 
     values[i] = i; 
    } 
    for (; i > 0; i--) { 
     r = rand.nextInt(i); 
     out.put(i, values[r]); 
     values[r] = values[i-1]; 
    } 
    return out; 
} 
+1

Your implementation,size = 100_000:1557 ms,size = 1_000_000:167130 ms。使用Collections.shuffle实现,size = 100_000:95 ms,size = 1_000_000:2934 ms。你说得快多快?除去'values'的元素有一个可怕的代价,而Collections.shuffle只交换元素。无论如何! – Dici 2014-08-31 16:54:49

+0

问题解决了,我不想开始辩论。我想说的是删除一个ArrayList的元素是O(n),所以你最后一个循环是O(n^2),而Collections.shuffle是O(n)。期。自己试试! http://pastebin.com/Se7CugK4 – Dici 2014-08-31 17:50:42

+0

是的,我同意.... – 2014-08-31 17:55:12