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

Random Number generated Array without duplicates and only odd Numbers

我正在尝试生成一个充满随机数的数组,没有重复项,并且它们都必须是偶数且大于 1。遗憾的是,在我的代码中,我的数组中经常出现“0”,但我真的不知道知道如何修复它。 这是代码:

{
    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;
                        }
            }
        }
    }

如何只得到奇数?

粗略地说,您有 3 个 'curves'(如带有 X 轴和 Y 轴的数字图表)可供您使用:

  • 线性有限均匀曲线

可通过 .nextInt() 和随机 class 中的大多数其他方法访问,例如 .nextBytes() - 这些会给你一个介于 0 和 B 之间的随机数(例如,B ,.nextByte()为256,.nextInt(5)为5,而且是均匀分布的,意思是:每个数字出现的可能性是一样的。

  • nextDouble()

.nextDouble() 是一个特殊的孩子 - 鉴于双打不精确,分布也不完美 - 你不能说:“它可以是 0 到 1 之间的任何数字”仅仅因为有之间有无限数量的数字,双打没有无限精度。出于随机目的,它是 'anything between 0 and 1, linear uniform',但请注意,用它进行映射会加剧 double 数学中固有的错误。

  • 高斯曲线

可通过 .nextGuassian() - a gaussian distributed curve 访问。中间的东西比更极端的数字更有可能。它继承了与 nextDouble 相同的一般精度问题。

而这 3 个就是您的全部。因此,如果您需要一个与上述 3 中的任何一个都不完全匹配的随机分布,则需要编写一个 'mapping operation' - 一个将上述 3 个中的一个作为输入并作为输出产生的函数随心所欲的随机数。

在您的具体情况下,您需要 'odd numbers'。这很容易做到:从 .nextInt() 开始,它给你任何数字,然后加 1 并乘以 2。现在你只有奇数了。

为了简单起见,取nextByte():它只能产生 256 个不同的值(0、1、2、3、....、255)。您可以制作一个包含 2 列的 table;左边包含每个数字。右边包含当你通过你的映射函数折腾它时它会发生什么。如果现在正确的列正是您想要的 - 瞧,你明白了。

因此,做一个函数:

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

然后使用mapToOdd(rnd.nextInt(maxValue)).

为什么你得到零。

原始数组(int[] 是原始数组)从全零开始。当您的算法没有将数字放入数组的每个 'cell' 中时,您会得到它开始的任何内容,即零。

不替换如何填充

这实际上比听起来要难。有 2 个选项:您选择的是只生成一个数字,检查该数字是否有效,如果无效,则重新开始。但是你引入了一个错误:当你生成一个偶数时,exist 将是 false,但是你的 if (!exist && x % 2 == 0) 函数也没有被输入 - 所以没有设置值(rArray[p] 仍然是 0),但是因为 exist 是假的,你的 while 循环不会循环。

另一种选择是首先生成所有个可能生成的数字,将它们存储在数组或列表中,将数组或列表打乱,然后只取前X个元素。

在 30% 点左右,效率翻转,你想要后者:假设你要 select 从 0-499 包含的随机数,并希望将它们存储在一个有 498 个槽的数组中,无需更换。您的算法(如果已经存在,则只需 re-random)将采用 AGES 作为最后几个数字。

int 的默认值为 0。当您的代码 returns 为奇数时,您没有为数组中的特定索引分配任何值。问题发生在下面 statements:

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

试试下面的代码:

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;
        }

    }

编辑: 这样做的构造方法如下: 导入 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;
        }

    }
}

当使用特定大小的 int[] 时,数组的值为 0,因为这是 int(基元)的默认值。

在您的循环中,您正在检查该值是否不存在并且是否为偶数,如果不存在,您将跳过数组中留下 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;
    }
  }
}

如果随机数是3,那将不存在,甚至都不存在。它将离开 while 循环,没有设置 rArray[p] 并且外循环将前进到下一个,留下 0.

你应该做的是首先检查值是否为偶数,如果不是则生成一个新的数字。

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;
    }
  }
}

现在使用流,这将更容易实现


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

会产生相同的结果。

有很多方法可以做到这一点。 答案中建议的一种有效方法是生成值,然后将它们打乱。

这可能是这样的。

  • 这里,maxValue是你要考虑的最大值。
  • 因为您只需要每隔一个值,数组的大小将是 maxValue/2.
  • 分配数组后,只需从 1 迭代到 maxValue/2 通过乘以 index by 2.
  • 用偶数填充数组
  • 现在是洗牌的时候了。如果您使用的是 Integer 数组,则可以执行 Collections.shuffle(Arrays.asList(array)) 来打乱列表,这也会打乱数组(因为数组支持列表)。但这对基元不起作用,因此包含一个用于 ints.
  • 基元数组的简单洗牌例程

它从 1 to maxValue 生成一个随机值,并将该位置的值与位置 maxValue 的值交换。然后 maxValue(或其代理项,在本例中为 i)递减,过程继续,结果返回一个打乱的数组。

请注意,返回数组的所有或第一个 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; 
}