2013-04-14 142 views
22

我想在Java中创建一组没有重复的随机数。Java生成非重复的随机数

比如我有一个数组从0万个的随机整数存储9999

这是我到目前为止有:

import java.util.Random; 
public class Sort{ 

    public static void main(String[] args){ 

     int[] nums = new int[10000]; 

     Random randomGenerator = new Random(); 

     for (int i = 0; i < nums.length; ++i){ 
      nums[i] = randomGenerator.nextInt(10000); 
     } 
    } 
} 

但上面的代码创建副本。我怎样才能确保随机数字不会重复?

+1

可能重复的[生成uniq ue随机数在Java](http://stackoverflow.com/questions/9423523/generate-unique-random-numbers-in-java) –

+2

但如果你删除重复的数字,那么他们不是随机 –

+1

你想要*以随机顺序排列数组中的所有* 10.000数字,还是您想要10.000个随机数字?因为你不能在0 - 9.999的范围内有10.000个随机数(然后他们不是随机的) – GameDroids

回答

32
Integer[] arr = {...}; 
Collections.shuffle(Arrays.asList(arr)); 

例如:

public static void main(String[] args) { 
    Integer[] arr = new Integer[1000]; 
    for (int i = 0; i < arr.length; i++) { 
     arr[i] = i; 
    } 
    Collections.shuffle(Arrays.asList(arr)); 
    System.out.println(Arrays.toString(arr)); 

} 
+1

Shuffle很棒,但首先应该创建包含数字的数组从0到9999,然后洗牌。另外,洗牌的时间复杂度是多少? – Martinsos

+1

@Martinsos我创建了数组并对其进行了整理。我不确定,但我认为洗牌的时间复杂度应该是O(n)。因为如果只是在数组内随机交换。 –

2

Achintya桑杰·贾在这里有正确的想法。不要考虑如何删除重复项,而是首先删除创建重复项的功能。

如果您想要使用一系列整数并想要随机化它们的顺序(手动,这很简单),请按照下列步骤操作。

  1. 创建大小为n的数组。
  2. 循环并将索引i处的每个值初始化为值i(或如果您希望将数字1至n而非0至n-1,则i + 1)。
  3. 最后,循环遍历数组,再次交换每个值的随机索引值。

你的代码可以被修改,看起来像这样:

import java.util.Random; 

public class Sort 
{ 
    // use a constant rather than having the "magic number" 10000 scattered about 
    public static final int N = 10000; 

    public static void main(String[] args) 
    { 
     //array to store N random integers (0 - N-1) 
     int[] nums = new int[N]; 

     // initialize each value at index i to the value i 
     for (int i = 0; i < nums.length; ++i) 
     { 
      nums[i] = i; 
     } 

     Random randomGenerator = new Random(); 
     int randomIndex; // the randomly selected index each time through the loop 
     int randomValue; // the value at nums[randomIndex] each time through the loop 

     // randomize order of values 
     for(int i = 0; i < nums.length; ++i) 
     { 
      // select a random index 
      randomIndex = randomGenerator.nextInt(nums.length); 

      // swap values 
      randomValue = nums[randomIndex]; 
      nums[randomIndex] = nums[i]; 
      nums[i] = randomValue; 
     } 
    } 
} 

如果我是你,我可能会打破这些块到单独的,较小的方法,而不是一个大的主要方法。

希望这会有所帮助。

0
public class Randoms { 

static int z, a = 1111, b = 9999, r; 

public static void main(String ... args[]) 
{ 
     rand(); 
} 

    public static void rand() { 

    Random ran = new Random(); 
    for (int i = 1; i == 1; i++) { 
     z = ran.nextInt(b - a + 1) + a; 
     System.out.println(z); 
     randcheck(); 
    } 
} 

private static void randcheck() { 

    for (int i = 3; i >= 0; i--) { 
     if (z != 0) { 
      r = z % 10; 
      arr[i] = r; 
      z = z/10; 
     } 
    } 
    for (int i = 0; i <= 3; i++) { 
     for (int j = i + 1; j <= 3; j++) { 
      if (arr[i] == arr[j]) { 
       rand(); 
      } 
     } 

    } 
} 
} 
6

一个简单的算法,为您提供没有重复的随机数字可以在Programming Pearls第p页找到。 127.

注意力:结果数组按顺序包含数字!如果您希望以随机顺序排列它们,则必须使用Fisher–Yates shuffle或通过使用列表并拨打电话Collections.shuffle()来随机排列阵列。

该算法的好处是,您不需要创建一个包含所有可能数字的数组,并且运行时复杂度仍然是线性的O(n)

public static int[] sampleRandomNumbersWithoutRepetition(int start, int end, int count) { 
    Random rng = new Random(); 

    int[] result = new int[count]; 
    int cur = 0; 
    int remaining = end - start; 
    for (int i = start; i < end && count > 0; i++) { 
     double probability = rng.nextDouble(); 
     if (probability < ((double) count)/(double) remaining) { 
      count--; 
      result[cur++] = i; 
     } 
     remaining--; 
    } 
    return result; 
} 
+1

注意:(re:你的“注意”部分)'Collections.shuffle'正在做一个Fisher-Yates shuffle,所以它不是一个“或 - 或”的情况。 –

+0

你是对的,'Collections.shuffle'做了Fisher-Yates洗牌,但是你需要一个List来使用它。 'Arrays.asList'需要数组的类型为'Integer'而不是'int'来正确地进行转换,那么你不必分配额外的内存。 编写Fisher-Yates随机播放避免了转换,并且不需要额外的内存。 – the

1

这个怎么样?

LinkedHashSet<Integer> test = new LinkedHashSet<Integer>(); 
Random random = new Random(); 
do{ 
    test.add(random.nextInt(1000) + 1); 
}while(test.size() != 1000); 

用户可以使用for循环遍历Set

2

如果你需要生成间隔号码,也可以只是这样:

Integer[] arr = new Integer[((int) (Math.random() * (16 - 30) + 30))]; 
for (int i = 0; i < arr.length; i++) { 
arr[i] = i; 
} 
Collections.shuffle(Arrays.asList(arr)); 
System.out.println(Arrays.toString(arr));` 

结果:

[1, 10, 2, 4, 9, 8, 7, 13, 18, 17, 5, 21, 12, 16, 23, 20, 6, 0, 22, 14, 24, 15, 3, 11, 19]

注:

如果您需要的是零不留下你可以把一个“如果”