生成与集合中给定的任何一个不同的随机索引

时间:2013-11-02 16:04:36

标签: java performance algorithm

我想生成从0size - 1的索引,统一但不同于给定集合excluded中的任何索引。

size大约为100.通常有1个,2个或3个exluded个索引。 excluded中的索引是唯一且未排序的。

理想情况下,标题将包含多个参数,可能是这样的:

int getRandomIndex(Random rand, int size, int... i)

或者,如果这个...多个参数很慢(是吗?),我们可以传递简单的int[] excluded数组等。

如何快速完成? getRandomIndex()被称为数百万次。

5 个答案:

答案 0 :(得分:4)

static int getRandomIndex(Random rand, int size, Integer... excludes) {
    List<Integer> excludeList = Arrays.asList(excludes);
    int number;
    do {
        number = rand.nextInt(size);
    } while (excludeList.contains(number));

    return number;
}

答案 1 :(得分:3)

您可以分配可能值的数组0..size-1,删除所有已知索引并从其余部分中选择随机元素。

如果索引数组已排序且所有值都是唯一的,则可以在没有中间值数组的情况下执行此操作:

int getRandomIndex(Random rand, int size, int... ii)
{
  int result = rand.nextInt(size - ii.length);
  for(int i : ii) {
    if(result >= i) {
      ++result; 
    }
  }

  return result;
}

编辑:我发现如果情况有误,请更正。

编辑:

int getRandomIndex(Random rand, int size, int i) {
  int result = rand.nextInt(size - 1);
  if(result >= i) {
    result++;
  }
}

int getRandomIndex(Random rand, int size, int i, int j) {
  int result = rand.nextInt(size - 2);
  if(i > j) {
    int tmp = j;
    j = i;
    i = tmp;
  }
  if(result >= i) {
    result++;
  }
  if(result >= j) {
    result++;
  }
  return result;
}

(i,j,k)的类似函数。

只调用rand.next一次的函数可能比任何函数更快,它会多次请求随机数。

答案 2 :(得分:1)

我的做法有点不同。要选择小于大小但不是i或j的随机数,您可以选择介于0和大小为3之间的随机数。如果该数字为i,则返回size-2,如果数字为j,则返回size-1。否则返回原始随机数。

i或j的边缘情况在2的大小范围内,但我将其留给感兴趣的读者。实际上我认为它只是运作正常。

这可以推广为选择小于不在整数数组中的大小的数字。选择小于大小的数字 - 数组长度 - 1.

答案 3 :(得分:1)

您可以使用Set快速查找

int getRandomIndex(Random rand, int size, Integer... i) {
    return getRandomIndex(rand, size, new HashSet<Integer>(Arrays.asList(i)));
}


int getRandomIndex(Random rand, int size, Set<Integer> x) {
    int result;
    do {
        result = (int) (rand.nextDouble() * size);
    } while (x.contains(result));
    return result;
}

如果预定义了所有索引的集合,那么您可以拥有Set x final static并在每次调用方法时备用它。

<强> EIDT

那么如果性能是一个问题那么我会说你的while(r == i || r == j || r == k)的第一种方法既不坏也不丑,只需要三次重载你的方法并调用你需要的那个,调用看起来就是与val-len-array相同。

您的评估速度不能超过(r == i || r == j || r == k)

int getRandomIndex(Random rand, int size, int i)
int getRandomIndex(Random rand, int size, int i, int j)
int getRandomIndex(Random rand, int size, int i, int j, int k)

答案 4 :(得分:0)

假设许多连续呼叫使用相同的大小和排除的值......

  • 首先,初始化所有允许索引的数组
  • 调用getRandomIndex时,只需选择此数组的随机元素
  • 即可

代码:

int[] indices;

void init(int size, Integer... excluded)
{
   indices = new int[size-excluded.length];
   int pos = 0;
   Set<Integer> excludedSet = new HashSet<Integer>(Arrays.asList(excluded));
   for (int i = 0; i < size; i++)
   {
      if (!excludedSet.contains(i))
      {
         indices[pos++] = i;
      }
   }
}

int getRandomIndex(Random random)
{
   return indices[random.nextInt(data.length)];
}

使用示例:

init(100, 50, 23, 10);
Random random = new Random();
for (int i = 0; i < 200; i++)
{
   System.out.println(getRandomIndex(random));
}