一个简单,公平,时间复杂度为 O(n)的洗牌算法。
什么是洗牌算法呢?其实就是将一些数据以公平随机的方式打乱顺序。这个算法,是由 Knuth(高纳德),也就是计算机程序设计艺术的作者发明的。下面我们直接进入正题。
假设有这样一个数组 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],我们使用 Knuth-Shuffle 算法将数据打乱。基本流程是这样的,从最后一个数开始,往前遍历,每一次,从当前数和第 1 个数之间,随机选择一个数,与当前数字进行交换(这里的随机选择就直接使用程序语言中的 Random 随机一个索引即可)。
例如上面的数组,第一次循环,当前数字为 10,我们从 1~10 之间,随机选择一个数,与 10 交换,这样第 9 个索引位就算洗完了,接下来就是第 8 个索引位,也就是数字为 9,我们从第 1 个索引位与第 8 个索引位之间,选择一个数,第 9 交换,这样第 8 个索引位也就洗完了...。这个算法之所以公平,是因为保证了每一个元素出现在每一个位置上的概率,都是一样的使用 VB.NET 编写的 Knuth 洗牌算法示例。该算法实现了您所描述的洗牌过程,并且保证了每个元素出现在每个位置的概率都是均等的。
Imports System
Imports System.Random
Module Module1
Sub Main()
Dim originalArray() As Integer = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
Dim shuffledArray() As Integer = ShuffleArray(originalArray)
Console.WriteLine("Original Array:")
For Each num In originalArray
Console.Write(num & " ")
Next
Console.WriteLine()
Console.WriteLine("Shuffled Array:")
For Each num In shuffledArray
Console.Write(num & " ")
Next
Console.WriteLine()
Console.ReadLine()
End Sub
Function ShuffleArray(ByVal original() As Integer) As Integer()
Dim shuffled() As Integer = original.Clone() ' 复制原数组
Dim rnd As New Random() ' 创建随机数生成器
For i As Integer = shuffled.Length - 1 To 1 Step -1
Dim j As Integer = rnd.Next(i + 1) ' 生成 0 到 i 之间的随机数
' 交换当前元素和随机选择的元素
Dim temp As Integer = shuffled[i]
shuffled[i] = shuffled[j]
shuffled[j] = temp
Next
Return shuffled ' 返回洗牌后的数组
End Function
End Module
在上面的代码中,ShuffleArray 函数接收一个整数数组作为输入,并返回一个新的已洗牌的数组。我们使用了 Random 类的 Next 方法来生成随机索引,并在每次迭代中交换当前元素和随机选择的元素。
注意,我们在循环中从数组的最后一个元素开始向前遍历,并且随机索引的范围是当前位置到数组的第一个元素之间(包括当前位置,但不包括数组的第一个元素之前的索引)。这是因为当我们处理到数组中的某个元素时,它之后的元素已经完成了洗牌,所以只需要考虑它之前的元素。
Main 函数中,我们创建了一个原始数组,调用 ShuffleArray 函数进行洗牌,并打印出原始数组和洗牌后的数组,以验证洗牌算法的正确性。