Mat*_*lls 192
以下实现使用Fisher-Yates算法.它在O(n)时间内运行并随机播放,因此比"随机排序"技术表现更好,尽管它是更多的代码行.请参阅此处了解一些比较性能测量.我使用过System.Random,非常适用于非加密目的.*
static class RandomExtensions
{
public static void Shuffle<T> (this Random rng, T[] array)
{
int n = array.Length;
while (n > 1)
{
int k = rng.Next(n--);
T temp = array[n];
array[n] = array[k];
array[k] = temp;
}
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
var array = new int[] {1, 2, 3, 4};
var rng = new Random();
rng.Shuffle(array);
rng.Shuffle(array); // different order from first call to Shuffle
Run Code Online (Sandbox Code Playgroud)
*对于较长的数组,为了使(极大)数量的排列同样可能,有必要通过多次迭代为每个交换运行伪随机数生成器(PRNG)以产生足够的熵.对于500个元素的阵列,只有500个元素的一小部分!使用PRNG可以获得排列.然而,Fisher-Yates算法是无偏的,因此随机播放将与您使用的RNG一样好.
mdb*_*mdb 157
如果您使用的是.NET 3.5,则可以使用以下IEnumerable coolness(VB.NET,而不是C#,但这个想法应该很明确......):
Random rnd=new Random();
string[] MyRandomArray = MyArray.OrderBy(x => rnd.Next()).ToArray();
Run Code Online (Sandbox Code Playgroud)
编辑:好的,这是相应的VB.NET代码:
Dim rnd As New System.Random
Dim MyRandomArray = MyArray.OrderBy(Function() rnd.Next()).ToArray()
Run Code Online (Sandbox Code Playgroud)
第二次编辑,以响应由于返回基于时间的序列而使System.Random"不是线程安全"和"仅适用于玩具应用程序"的评论:如我的示例中所使用的,Random()完全是线程安全的,除非您允许重新输入数组随机化的例程,在这种情况下,您将需要类似的东西lock (MyRandomArray),以免损坏您的数据,这也将保护您的数据rnd.
此外,应该很好地理解System.Random作为熵源不是很强.如MSDN文档中所述,System.Security.Cryptography.RandomNumberGenerator如果您正在执行与安全性相关的任何操作,则应使用从中派生的内容.例如:
using System.Security.Cryptography;
Run Code Online (Sandbox Code Playgroud)
...
RNGCryptoServiceProvider rnd = new RNGCryptoServiceProvider();
string[] MyRandomArray = MyArray.OrderBy(x => GetNextInt32(rnd)).ToArray();
Run Code Online (Sandbox Code Playgroud)
...
static int GetNextInt32(RNGCryptoServiceProvider rnd)
{
byte[] randomInt = new byte[4];
rnd.GetBytes(randomInt);
return Convert.ToInt32(randomInt[0]);
}
Run Code Online (Sandbox Code Playgroud)
Pit*_*rou 18
你正在寻找一种改组算法,对吧?
好吧,有两种方法可以做到这一点:聪明 - 但人 - 总是似乎误解 - 它 - 并且 - 它错了 - 所以 - 也许 - 它不是那么聪明 - 毕竟方式,和愚蠢的岩石,但谁关心,因为它的工作方式.
- 创建第一个数组的副本,但标记每个字符串应该是一个随机数.
- 根据随机数对重复数组进行排序.
此算法运行良好,但请确保您的随机数生成器不太可能标记具有相同数字的两个字符串.由于所谓的生日悖论,这种情况比你想象的更频繁.其时间复杂度为O(n log n).
我将其描述为递归算法:
要改组大小为n的数组(索引在[0 .. n -1] 范围内):
如果n = 0如果n > 0
- 没做什么
- (递归步骤)混洗数组的前n -1个元素
- 选择[0 .. n -1] 范围内的随机索引x
- 将索引为n -1的元素与索引x处的元素交换
迭代等价物是通过数组遍历迭代器,随机交换随机元素,但请注意,在迭代器指向的元素之后,您不能与元素交换.这是一个非常常见的错误,并导致有偏见的洗牌.
时间复杂度为O(n).
该算法简单但效率不高,O(N 2).所有"order by"算法通常为O(N log N).它可能在数十万个元素下面没有区别,但它适用于大型列表.
var stringlist = ... // add your values to stringlist
var r = new Random();
var res = new List<string>(stringlist.Count);
while (stringlist.Count >0)
{
var i = r.Next(stringlist.Count);
res.Add(stringlist[i]);
stringlist.RemoveAt(i);
}
Run Code Online (Sandbox Code Playgroud)
它的O(N 2)之所以微妙:List.RemoveAt()是一个O(N)操作,除非你从结尾顺序删除.
| 归档时间: |
|
| 查看次数: |
129681 次 |
| 最近记录: |