簡體   English   中英

每次在迭代中從int數組中選擇不同的隨機元素?

[英]Picking different random elements from int array each time in iteration?

我有一個int向量,例如int[] A = {6, 1, 5, 3, 4, 2} ,我需要在三個步驟中隨機選擇兩個不同的元素,並且每個步驟都應該從其他步驟中挑選出不同的元素。

例如:

  1. 選擇2、5
  2. 選擇6、3
  3. 選擇4、1

我嘗試這樣做,但失敗了很多次。 我將非常感謝您的幫助。 這是我的最后一個代碼。

public class T8 {
    public static void main(String[] args) {
        int n=5,   d=2, r,  i,  j;
        int[] B = new int [d];
        Random rand=new Random(); 
        System.out.println("d = "+d);
        Integer[] A = {10,12,3,4,5};
        List<Integer> list = new ArrayList<Integer>(Arrays.asList(A));
        for(j=0; j<d; j++){
            r = rand.nextInt(n);
            B[j] = A[r];
            System.out.print(B[j]+"   ");
            list.remove(r);
            A = list.toArray(new Integer[0]);
            n=n-1;
        }

        System.out.println("");
        for(j=0; j<n; j++){
            System.out.print(A[j]+"   ");
        }
    }
}

不是最佳方法 :可以使用random.nextInt,並且每次生成隨機數時,請檢查其是否唯一,如果不生成新的隨機索引。 例如

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

public class RandomPicker {

    public static void main(String[] args) {

        int[] arr = {6, 1, 5, 3, 4, 2};
        Random random = new Random();
        Set<Integer> randoms = new HashSet<>();
        while (arr.length != randoms.size()) {
            int i = nextRandomIndex(arr, random, randoms);
            int j = nextRandomIndex(arr, random, randoms);
            System.out.printf("%d,%d\n", arr[i], arr[j]);
        }
    }

    private static int nextRandomIndex(int[] arr, Random random, Set<Integer> randoms) {
        int i = random.nextInt(arr.length);
        while (randoms.contains(i)) {
            i= random.nextInt(arr.length);
        }
        randoms.add(i);
        return i;
    }
}

可能的輸出

4,1
6,3
5,2

更好的方法是先對數組進行隨機排序,然后對其進行迭代(如果您不想修改數組,則將原始數組的副本傳遞給shuffle方法)。 例如

import java.util.Arrays;
import java.util.Random;

public class RandomPicker {

    public static void main(String[] args) {

        int[] arr = {6, 1, 5, 3, 4, 2};
        int[] copy = Arrays.copyOf(arr, arr.length);
        shuffle(copy);
        int index = 0;
        for (int i = 0; i < arr.length / 2; i++) {
            System.out.printf("%d, %d\n",copy[index], copy[++index]);
        }
    }

    private static void shuffle(int[] arr)
    {
        int index;
        int temp;
        Random rand = new Random();
        int i = arr.length - 1;
        while ( i > 0)
        {
            index = rand.nextInt(i + 1);
            temp = arr[index];
            arr[index] = arr[i];
            arr[i] = temp;
            i--;
        }
    }
}

您可以通過多種方式執行此操作:

  1. 將數組元素復制到List ,然后從列表中隨機刪除元素。

  2. 使用(弱)偽隨機數生成器以可預測的方式循環遍歷所有索引。

  3. 為您之前返回的所有元素創建一個HashSet

  4. 使用shuffle方法就地重組輸入數組,然后一次從索引0開始一次返回一個元素,直到達到length - 1為止。

  5. 如果您無法更改輸入數組,則創建一個數組,將值0填充為length - 1 ,將其洗牌,然后使用其值作為第一個數組的索引逐步遍歷該數組。

@ sol4me的解決方案(由上面的3.和5.混合而成)具有有趣的屬性。 計算行為是概率性的:

  • 當您到達序列的末尾時,“警報”增長之前查找和返回未使用的索引所花費的時間。

  • 理論上最壞的情況是nextRandomIndex永不終止。 (只有在您的隨機數生成器有偏見的情況下,這種情況才會發生。)

  • 對於“完美”的隨機數生成器, nextRandomIndex執行的迭代次數是有限的,但是我們不能對其設置上限。

  • 對於偽隨機數生成器,生成器的循環長度是迭代次數的上限。


您嘗試的解決方案接近我建議的第一個解決方案。 但是一個問題是

    List<Integer> list = new ArrayList<Integer>(Arrays.asList(A));

無法更改其長度的數組上創建“視圖”。 如果創建一個ArrayList ,然后數組元素復制到列表中,則不會獲得在remove中看到的異常。

另一個問題是:

    A = list.toArray(new Integer[0]);

效率很低。 不必將列表轉換回數組。 請保留下一次清單。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM