背景:
我们从n个不重复的数字中中取出m个不能重复的数字。
洗牌算法理念:
我们把n个数打乱,然后从从前到后取出m个数,就能达到我们想要的效果。
洗牌算法也大致分为三类,抽牌,换牌,插排
抽牌:
Fisher–Yates shuffle 算法是最早提出的,他的原理就是:将最后一个数和前面任意 n-1 个数中的一个数进行交换,然后倒数第二个数和前面任意 n-2 个数中的一个数进行交换。
换牌:
for(int i = n - 1; i >= 0 ; i -- )
swap(arr[i], arr[rand(0, i)]) // rand(0, i) 生成 [0, i] 之间的随机整数
大家可以先简单的理解一下这个循环在做什么。其实非常简单,i 从后向前,每次随机一个 [0...i] 之间的下标,然后将 arr[i] 和这个随机的下标元素,也就是 arr[rand(0, i)] 交换位置。
大家注意,由于每次是随机一个 [0...i] 之间的下标,所以,在每一轮,是可以自己和自己交换的。