简体   繁体   English

随机数生成的数组没有重复且只有奇数

[英]Random Number generated Array without duplicates and only odd Numbers

I am trying to generate an array filled with random numbers, no duplicates and all of them have to be even and greater than 1. Sadly in my code i often get a "0" in my array but i dont really know how to fix it.我正在尝试生成一个充满随机数的数组,没有重复项,并且它们都必须是偶数且大于 1。可悲的是,在我的代码中,我的数组中经常出现“0”,但我真的不知道如何修复它. Here is the code:这是代码:

{
    public int[] rArray; // our array
    RandomArray(int arrayLength, int MaxValue)
    {
        rArray = new int[arrayLength];
        Random randNum = new Random();
        for(int p=0; p<arrayLength;p++)
            for (int i = 0; i <= rArray.length; i++)
            {
                boolean exist = true; 
                while (exist)
                {
                    exist = false;// 
                    int x = randNum.nextInt(2,MaxValue); 
                    for (int k = 0; k < i; k++) 
                    {
                        if (x == rArray[k] ) 
                        {
                            exist = true;
                            break;
                        }
                    }
                        if (!exist && x % 2 == 0) 
                        {
                            rArray[p] = x;
                        }
            }
        }
    }

The default value for int is 0. When your code returns an odd number you are not assigning any value to the specific index in the array. int 的默认值为 0。当您的代码返回奇数时,您没有为数组中的特定索引分配任何值。 The issue is happening in the below statements:问题发生在以下statements:

if (!exist && x % 2 == 0) 
{
  rArray[p] = x;
}

Try the below code:试试下面的代码:

private static int[] getArray(int arrayLength, int maxValue) {
        int[] rArray = new int[arrayLength];
        Random randNum = new Random();
        for (int p = 0; p < arrayLength; p++)
            for (int i = 0; i <= rArray.length; i++) {
                boolean exist = true;
                int x = getRandomNumber(randNum, maxValue);
                while (exist) {
                    exist = false;//
                    for (int k = 0; k < i; k++) {
                        if (x == rArray[k]) {
                            exist = true;
                            break;
                        }
                    }
                    x = getRandomNumber(randNum, maxValue);
                }
                rArray[p] = x;
            }
        return rArray;
    }


    private static int getRandomNumber(Random random, int maxValue) {
        while (true) {
            int i = random.nextInt(maxValue);
            if (i % 2 == 0 && i != 0)
                return i;
        }

    }

Edit: The constructor way of doing it is below: import java.util.Random;编辑:构造方法如下:import java.util.Random;

public class RandomArray {
    public int[] rArray;

    RandomArray(int arrayLength, int MaxValue) {
        int[] rArray = new int[arrayLength];
        Random randNum = new Random();
        for (int p = 0; p < arrayLength; p++)
            for (int i = 0; i <= rArray.length; i++) {
                boolean exist = true;
                int x = getRandomNumber(randNum, MaxValue);
                while (exist) {
                    exist = false;//
                    for (int k = 0; k < i; k++) {
                        if (x == rArray[k]) {
                            exist = true;
                            break;
                        }
                    }
                    x = getRandomNumber(randNum, MaxValue);
                }
                rArray[p] = x;
            }
    }


    private static int getRandomNumber(Random random, int maxValue) {
        while (true) {
            int i = random.nextInt(maxValue);
            if (i % 2 == 0 && i != 0)
                return i;
        }

    }
}

How do you get only odd numbers?你怎么只得到奇数?

You have, in broad strokes, 3 'curves' (as in, a number graph with an X and a Y axis) available to you:粗略地说,您可以使用 3 条“曲线”(如带有 X 轴和 Y 轴的数字图表):

  • The linear limited uniform curve线性有限均匀曲线

Accessible via .nextInt() and most of the other methods in the Random class such as .nextBytes() - these give you a random number between 0 and B (B is, for example, 256 for .nextByte() , and 5 for .nextInt(5) , and it is uniformly distributed, meaning: Each number is equally likely to come up.可通过.nextInt()和 Random class 中的大多数其他方法访问,例如.nextBytes() - 这些为您提供 0 和 B 之间的随机数(例如,对于 .nextByte() ,B 为 256,对于.nextByte()为 5 .nextInt(5) ,它是均匀分布的,意思是:每个数字出现的可能性相同。

  • nextDouble()

.nextDouble() is a special kid - given that doubles aren't precise, the distribution isn't perfect - you can't say: "It can be any number between 0 and 1" simply because there are an infinite amount of numbers between there, and doubles do not have infinite precision. .nextDouble()是一个特殊的孩子——考虑到双打不精确,分布也不完美——你不能说:“它可以是 0 到 1 之间的任何数字”仅仅因为有无限数量的数字在那之间,双打没有无限的精度。 For random purposes, it's 'anything between 0 and 1, linear uniform', but be aware that going on a mapping spree with this is going to compound the errors inherent in double math.出于随机目的,它是“0 到 1 之间的任何值,线性均匀”,但请注意,使用它进行映射会加剧double数学中固有的错误。

  • The guassian curve高斯曲线

Accessible via .nextGuassian() - a gaussian distributed curve .可通过.nextGuassian() -高斯分布曲线访问。 Stuff in the middle is more likely than more extreme numbers.中间的东西比更极端的数字更有可能。 It inherits the same general precision malaise that nextDouble does.它继承了与nextDouble相同的一般精度问题。

And those 3 are all you have.而这 3 个就是你所拥有的。 Thus, if you have a need for a random distribution that doesn't exactly match any of the above 3, you need to cook up a 'mapping operation' - a function that takes as input one of the above 3 and as output produces random numbers precisely as you desire.因此,如果您需要一个与上述 3 中的任何一个都不完全匹配的随机分布,则需要编写一个“映射操作”- function 将上述 3 个中的一个作为输入,而 output 产生随机完全按照您的意愿编号。

In your specific case, you want 'odd numbers'.在您的特定情况下,您需要“奇数”。 That's easy enough to do: Start with .nextInt() which gives you any number, then, add 1 and multiply by 2. Now you have only odd numbers.这很容易做到:从.nextInt()开始,它给你任何数字,然后加 1 并乘以 2。现在你只有奇数了。

Take nextByte() to keep things simple: It can only produce 256 different values (0, 1, 2, 3, ...., 255).nextByte()保持简单:它只能产生 256 个不同的值(0、1、2、3、....、255)。 You could make a table with 2 columns;您可以制作一个包含 2 列的表格; the left contains each of those numbers.左边包含每个数字。 The right contains what happens to it when you toss it through your mapping function. If the right column now is precisely what you desire - voila, you got it.右侧包含当您通过映射 function 抛出它时发生的情况。如果现在右侧的列正是您想要的 - 瞧,您得到了它。

Thus, make a function:因此,制作一个 function:

public static int mapToOdd(int in) {
  return 1 + in * 2;
}

and then use mapToOdd(rnd.nextInt(maxValue)) .然后使用mapToOdd(rnd.nextInt(maxValue))

Why you are getting zeroes.为什么你得到零。

primitive arrays (and int[] is a primitive array) start out with all zeroes.原语 arrays(并且int[]是一个原语数组)从全零开始。 When your algorithm does not put a number into each 'cell' of your array, then you get whatever it started out as, which is a zero.当您的算法没有将数字放入数组的每个“单元格”时,您会得到它开始的任何内容,即零。

How to fill without replacement如何填充而不更换

This is actually harder than it sounds.这实际上比听起来更难。 There are 2 options: The one you took is to just generate a number, check if the number is valid, and if not, start over.有 2 个选项:您选择的是只生成一个数字,检查该数字是否有效,如果无效,则重新开始。 But you've introduced an error: When you generate an even number, exist will be false , but your if (!exist && x % 2 == 0) function doesn't get entered either - so no value is set ( rArray[p] remains 0), but because exist is false, your while loop doesn't loop.但是你引入了一个错误:当你生成一个偶数时, exist将为false ,但是你的if (!exist && x % 2 == 0) function 也没有被输入 - 所以没有设置值( rArray[p]保持为 0),但是因为exist为假,所以您的 while 循环不会循环。

Another option is to first generate all numbers possible to generate, store them in an array or list, shuffle the array or list, and then just take the first X elements.另一种选择是首先生成所有可能生成的数字,将它们存储在数组或列表中,打乱数组或列表,然后只取前 X 个元素。

At around the 30% point, efficiency flips over and you want the latter: Imagine you are going to select random numbers from 0-499 inclusive and want to store them in an array with 498 slots, without replacement.在大约 30% 点,效率翻转,你想要后者:假设你要从 0-499 中获取 select 个随机数,并希望将它们存储在一个有 498 个槽的数组中,而不需要替换。 Your algorithm (just re-random if it's already there) is going to take AGES for the final few numbers.您的算法(如果已经存在则重新随机)将采用AGES作为最后几个数字。

When using an int[] of a certain size the values of the array are 0, as that is the default value of an int (a primitive).当使用特定大小的int[]时,数组的值为 0,因为这是int (基本类型)的默认值。

In your loop you are checking if the value doesn't exist and is even, if not you skip over an element in the array leaving the 0.在您的循环中,您正在检查该值是否不存在并且是否为偶数,如果不存在,您将跳过数组中留下 0 的元素。

for (int i = 0; i <= rArray.length; i++) {
  boolean exist = true; 
  while (exist) {
    exist = false;// 
    int x = randNum.nextInt(2,MaxValue); 
    for (int k = 0; k < i; k++) {
      if (x == rArray[k] ) {
        exist = true;
        break;
      }
    }
    if (!exist && x % 2 == 0) {
      rArray[p] = x;
    }
  }
}

If the random number is 3, that will not exist, and isn't even either.如果随机数是 3,那将不存在,甚至都不存在。 It will leave the while loop, not having set rArray[p] and the outer loop will advance to the next one, leaving the 0.它将离开while循环,没有设置rArray[p]并且外层循环将前进到下一个,留下 0。

What you should do is first check if the value is even, if not generate a new numnber.您应该做的是首先检查该值是否为偶数,如果不是则生成一个新数字。

for (int i = 0; i < rArray.length; i++) {
  boolean exist = true; 
  while (exist) {
    exist = false;// 
    int x = 1;
    while (((x = randNum.nextInt(2, MaxValue)) % 2) != 0) {}
                }
    for (int k = 0; k < i; k++) {
      if (x == rArray[k] ) {
        exist = true;
        break;
      }
    }
    if (!exist) {
      rArray[i] = x;
    }
  }
}

Now using streams this would be a lot easier to achieve现在使用流,这将更容易实现


rArray= ThreadLocalRandom.current().ints(2, MaxValue)
                .filter(it -> (it % 2) == 0)
                .distinct().limit(arrayLength).toArray();

Would yield the same result.会产生相同的结果。

There are many ways to do this.有很多方法可以做到这一点。 One efficient way as suggested in rzwitserloot's answer is to generate the values and then shuffle them. rzwitserloot 的回答中建议的一种有效方法是生成值,然后对它们进行洗牌。

Here is how that might work.这可能是这样的。

  • here, maxValue is the largest value you want to consider.此处, maxValue是您要考虑的最大值。
  • since you only want every other value, the size of the array would be maxValue/2 .由于您只需要所有其他值,因此数组的大小将为maxValue/2
  • after allocating the array, just iterate from 1 to maxValue/2 filling an array with even values by multiplying the index by 2 .分配数组后,只需从 1 迭代到maxValue/2通过将index by 2来用偶数填充数组。
  • now it's time to shuffle the values.现在是洗牌的时候了。 If you were using Integer arrays you could do Collections.shuffle(Arrays.asList(array)) to shuffle the list which also shuffles the array (since the array backs the list).如果您使用的是Integer arrays,则可以执行Collections.shuffle(Arrays.asList(array))来打乱列表,这也会打乱数组(因为数组支持列表)。 But that won't work for primitives so included is a simple shuffle routine for primitive arrays of ints .但这对基元不起作用,因此包括一个简单的洗牌例程,用于ints的基元 arrays。

It generates a random value from 1 to maxValue and swaps the value at that location with the value at location maxValue .它生成一个从1 to maxValue的随机值,并将该位置的值与位置maxValue的值交换。 Then maxValue (or its surrogate, in this case i ) is decremented and the process continues, resulting in a shuffled array which is returned.然后maxValue (或其替代项,在本例中为i )递减并且该过程继续,导致返回一个混洗数组。

Note that either all or the first limit values of the returned array will satisfy the requirement (assuming of course that limit <= maxValue/2 )请注意,返回数组的所有或第一个limit值都将满足要求(当然假设limit <= maxValue/2


public static int[] gen(int maxValue) {
      maxValue/=2;
      int[] v = new int[maxValue];
      for (int i = 1; i <= maxValue; i++) {
          v[i-1] = i*2;
      }
      // time so shuffle.

      Random r = new Random();
      for (int i = maxValue-1; i >= 0; i--) {
          int slot = r.nextInt(i+1);
          int t = v[i];
          v[i] = v[slot];
          v[slot] =t;
      }
      
     return v; 
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM