为什么在排序中使用Random导致

我尝试使用任一代码来改组字节(List)列表:

myList.Sort((a, b) => this._Rnd.Next(-1, 1)); 

要么

 myList.Sort(delegate(byte b1, byte b2) { return this._Rnd.Next(-1, 1); }); 

他们抛出以下错误:

无法排序,因为IComparer.Compare()方法返回不一致的结果。 要么值不等于自身,要么重复一个值与另一个值进行比较会产生不同的结果。 x:'{0}’,x的类型:'{1}’,IComparer:'{2}’。

使用随机而不是字节的比较函数有什么问题?

我尝试使用LINQ函数,它的工作原理。

 var myNewList = myList.OrderBy(s => Guid.NewGuid()); var myNewList = myList.OrderBy(s => this._Rnd.NextDouble()); 

我确实读过这些方法比Fisher-Yates shuffle慢,只给O(n)运行时。 但只是想知道使用Sort函数和随机。

因为正如错误所说,Random不一致。 在给定相同参数时,您必须具有始终返回相同结果的比较器。 否则排序将不一致。

Knuth有一个随机排序算法,它的工作方式类似于插入排序,但您在现有数组中将值与随机选择的位置交换。

不仅需要比较关系保持一致 ,还需要强加总排序 。 例如,你不能说“袜子比鞋子小,衬衫既不小于裤子也不比裤子大”,等等等等,把它喂成排序算法并期望从另一端得到拓扑 。 比较排序称为比较排序, 因为它们需要格式良好的比较关系 。 特别是,如果比较关系不一致,传递和总排序,则快速排序可以永久运行或给出无意义的结果。

如果您想要的是随机播放,那么实施Fischer-Yates shuffle。 (做得正确;即使算法很简单,它几乎总是被错误地实现。)如果你想要的是拓扑排序,那么实现拓扑排序。 使用正确的工具完成工作。

排序算法通常通过定义比较函数来工作。 算法将重复比较要排序的序列中的两个项目,如果它们的当前顺序与所需顺序不匹配则交换它们。 算法之间的差异主要与在给定情况下找到最有效的方法来进行所有比较有关。

在进行所有这些比较的过程中,序列中相同的两个元素需要不止一次进行比较是很常见的! 使用非数字数据使这更容易,假设您有值为“红色”和“Apple”的项目。 随机比较器选择“Apple”作为第一次比较的较大项目。 稍后,如果随机比较器选择“红色”作为更大的项目,并且此来回继续,则最终可能会出现算法永远不会完成的情况

大多数情况下你很幸运 ,没有任何反应。 但有时候你却没有。 .Net非常适合不仅仅是永远运行并且防止这种情况,但它确实(并且应该! )当这些警卫检测到不一致的顺序时抛出exception。

当然,在一般情况下处理此问题的正确方法是通过Knuth-Fisher-Yates shuffle。

值得一提的是,有时简单的Fisher-Yates是不合适的。 一个例子是需要随机化一个未知长度的序列…假设您想要随机重新排列从网络流接收的数据,而不知道流中有多少数据,并尽快将数据提供给工作人员其他地方。

在这种情况下,您无法完全随机化该数据。 在不知道流的长度的情况下,您没有足够的信息来正确地进行随机播放,即使您这样做,您可能会发现长度只要将其全部保存在RAM中甚至在磁盘上都不切实际。 或者您可能会发现流不会在几个小时内完成,但您的工作线程需要更快地完成。 在这种情况下,你可能会满足(并理解这是“解决”很重要)一个算法,它加载一个足够长度的缓冲区,随机化缓冲区,将大约一半的缓冲区输出到工作线程,然后重新 – 填充缓冲区的空白部分以重复该过程。 即使在这里,您也可能使用Knuth-Fisher-Yates进行随机化缓冲的步骤。