【问题标题】:Why does using Random in Sort causing [Unable to sort IComparer.Compare error]为什么在排序中使用随机导致[无法排序 IComparer.Compare 错误]
【发布时间】:2010-11-09 02:34:21
【问题描述】:

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

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());

我确实读到这些方法比仅给出 O(n) 运行时间的 Fisher-Yates shuffle 慢。但只是想知道使用排序功能和随机。

【问题讨论】:

    标签: c# linq list sorting random


    【解决方案1】:

    不仅要求比较关系一致,还要求强加全序。例如,您不能说“袜子比鞋子小,衬衫既不小于也不大于裤子”等等等等,将其输入到排序算法中并期望得到 拓扑 排序另一端。比较排序被称为比较排序因为它们需要一个格式良好的比较关系。特别是,如果比较关系不是一致的、传递的和全序的,快速排序可能会永远运行或给出无意义的结果。

    如果您想要的是随机播放,那么请实施 Fischer-Yates 随机播放。 (正确执行;即使算法很简单,但几乎总是执行错误。)如果您想要的是拓扑排序,那么请实现拓扑排序。为工作使用正确的工具。

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 那么排序函数检查排序函数的一致性?我认为这只是一个虚拟排序算法,它只遵循比较器的返回值,无论它返回什么。但我猜如果它在内部使用快速排序,该函数可能已经出现故障,因为它在找到要递归的索引时获得不同的值。
      • 排序旨在产生一致的结果。你误用了!
      • 有道理。我猜 orderby 是正确使用的功能。谢谢
      【解决方案3】:

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

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

      大多数情况下你会得到幸运,但什么也没有发生。但有时你不会。 .Net 不仅可以永远运行并防止这种情况发生,而且它确实(并且应该!)在这些保护检测到不一致的顺序时抛出异常。

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

      进一步值得一提的是,有时简单的 Fisher-Yates 并不合适。一个例子是需要随机化一个未知长度的序列......假设你想要随机重新排列从网络流中接收到的数据,而不知道流中有多少数据,并尽快将这些数据提供给工作人员在别处穿线。

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

      【讨论】:

        猜你喜欢
        • 2016-07-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多