Something that could be faster than shuffling the entire array:
java.util.Random r = new java.util.Random(); int c1 = r.nextInt(52), c2 = r.nextInt(51), c3 = r.nextInt(50); if(c2 >= c1) c2++; if(c3 >= Math.min(c1, c2)) c3++; if(c3 >= Math.max(c1, c2)) c3++; System.out.println("Card 1: " + rank[c1]); System.out.println("Card 2: " + rank[c2]); System.out.println("Card 3: " + rank[c3]);
In fact, some temporary tests that I used using a generalized (slower) form, this algorithm against Collections.shuffle (screenshot here ) shows that this method is about 3.7 times faster for 3 cards , and in practice faster for Pick up to 24 random cards.
To explain the algorithm to those in doubt:
Probability
We select random numbers - first one of 52. If we need to remove this card, then choose another one that will be one of 51 ... so we are fine with the range of random numbers from the indices we selected.
If we collected and removed from the array, we simply took out the element at index 1, and then took out the element at index 2 and the same for index 3.
What I am doing above adjusts the indices in the same way as outputting elements from an array.
For index two, we have a number, which can be any number from 0 to 50. But let's pretend that we pulled out a card with index 6 ...
This means that instead of a random number spreading in the range from 0 to 50, now we want one spread evenly in the range 0-5 and 7-51. This is another 51 ways. We do this by adding 1 to our second index if it is> = 6. Now we have a number over the correct range with the correct distribution and equal probability if it hits any of the allowed indices.
The same slightly more complex logic applies to the third card: there are no two spots in the deck, so we adjust the third index to cover the available ranges. First, if it is equal to or greater than the first missing position, slide it up. Then, if it is equal to or greater than the second, slide it again. This does not shift the selection to higher values - all we do is avoid indexes that have already been used.
There are no distortions in probabilities.
Efficiency
The comments mentioned that this algorithm and the one that uses Collections.shuffle have the same complexity (i.e. O (n)), and this method is somewhat less readable. The first point is that this algorithm is more complex; those. shuffle the entire array, this is O (n ^ 2). For low n, this algorithm is more efficient. And, I think, the difference in efficiency guarantees the victim a readability. For comparison:
Collections.shuffle
- choose random number
- remove item from list
- insert item into list
- repeat 51 more times
This method
- choose random number
- choose random number
- choose random number
- Up to 3 steps
This ignores the transfer from the array to the container required when using the first method. The inevitable conclusion is that this method is much more efficient.
BTW - you can visualize the nature of O (n ^ 2) when you think about choosing 4 cards - which requires up to 6 increments ... 5 cards, up to 10 ... 6 cards, up to 15 ... for n, (n ^ 2 - n) / 2
Summarizing
In this example, I used Math.min and Math.max as an easy way to sort a list of two elements. In the general case (that is, by selecting "n" [1-52 inclusive] non-repeating random cards), we need to sort the list of 52 items. This can be done in the worst case O (n), using insertion sorting while maintaining an ordered list of selected indices. Selecting a new random index is done using
- Select a new random index using
Random.nextInt(52 - selectedIndexListSize) - Iterate over a sorted list, with each node, incrementing our selected index if that value is> = node, stopping if it is less
- output map at the selected index in the array
- insert our selected index into the sorted list, the moment we stopped
This is O (n) for each choice - but up to 52 samples are given, making it O (n ^ 2).
However, in terms of efficiency, this algorithm is more efficient when m ^ 2 <n, (or, more precisely, whenever m + (m ^ 2-m) / 2 <n), where n is 52 and m is the number selected cards. Thus, this method is more efficient for selecting 7 or less cards (or using a more accurate calc, 9 or less), and therefore, and obviously, is more effective for choosing 3.