使用随机比较委托的List.Sort可以无限运行吗?

时间:2011-06-01 18:20:47

标签: .net algorithm sorting random

我正在调查和性能测试随机化有序集合的各种方法,我正在考虑传递一个只是随机返回比较结果的比较委托的选项。例如:

int RandomComparison<T> (T x, T y)
{
    return this.random.Next (-1, 2);
}

但是,由于我不知道引擎盖下使用的排序算法,我不知道这是否可能导致排序逻辑永远不会完成。虽然这种方法在性能方面看起来通常不可靠,但我想知道它是否真的危险地无法使用?

6 个答案:

答案 0 :(得分:4)

答案 1 :(得分:4)

我猜你的怀疑是正确的。构建这种类型代码的整个前提是如果A&lt; B和B&lt; C然后A&lt;下进行。

您可以将随机数与集合中的每个项相关联,然后对该值进行标准排序。

答案 2 :(得分:3)

List.Sort实际上是记录使用QuickSort(没有给出额外的细节),但我会忽略这一点,而是赞成谈论一般的排序......

我怀疑对于任何合理的排序算法,这个比较器导致操作以概率1终止,因为当N趋于无穷大时,持续N步的概率趋于0。事实上,我认为在很多情况下都存在严格的上限。

原因是有可能(以非零概率发生)随机比较器可能恰好返回一致的结果,以便在一行中进行足够的比较(可能是O(n log n),或者O( n ^ 2)用于插入排序)算法“认为”它已完成。只要最终发生这种情况,我就会期望它终止排序。

然而,我无法确定这一点,因为在这个短暂的一致性阶段之前,算法进入不可恢复的状态绝不是不可能的。我只是预感到实际的排序算法,这种情况不会发生。事实上,对于许多算法来说,无论比较器有多荒谬,问题都会无情地变小,从而产生一个硬限制。特别是QuickSort通过重复分区数组来工作 - 如果比较器是随机的,那么这将导致无意义的分区,但只要不存在由于不一致而发生的实际错误,数组仍然会被分成两部分用于递归。事实上,“顶部”部分中的元素在第二次询问时不会比枢轴更大,这根本不重要,因为它们永远不会再与它进行比较。

无论如何,它可能需要很长时间,足以构成对大多数实际目的而言“危险”。例如,冒泡排序只会持续搅拌,直到连续获得n个负面结果,无需移动任何东西即可完成扫描。这需要花费预期的时间2^n或其左右(特别是List.Sort不是泡泡排序,我用它来说明一般情况下排序可能会发生什么)。根据实施细节,您可能会发现,由于“不可能”发生,您访问越界,比“完成”更多次。

操作肯定必然随机化所有排列的集合。再次注意,QuickSort选择一个轴,然后围绕它进行分区。给定这个随机比较器(并且,再次假设没有像越界访问那样的实际错误),第一个选择的枢轴在阵列的最右侧结束的概率是1 ^ 2 ^(n-1) )(因为所有其他元素必须在其左边排序,每个元素有一半的机会),而在均匀随机选择的排列中,该概率应该是n中的1。当它“应该”均匀时,第一个选择的枢轴在阵列上分布在钟形曲线上。

答案 3 :(得分:2)

是的,使用随机比较可以使排序算法以几种不同的方式起作用。它可能会产生偏差,甚至会卡住。

用于混洗集合的最有效算法是Fisher-Yates shuffle。它会在O(n)中对集合进行洗牌,这比任何排序算法都要好。

答案 4 :(得分:1)

正如许多人已经提到的,使用随机比较函数进行排序不会产生排列的均匀分布,因此不应使用。但无论如何要回答这个问题......


从理论的角度来看,是的你可以根据你的排序算法选择无限地挂起。

例如,此冒泡排序一直持续到没有进行交换:

From Wikipedia

procedure bubbleSort( A : list of sortable items )
  do
    swapped = false
    for each i in 1 to length(A) - 1 inclusive do:
      if A[i-1] > A[i] then
        swap( A[i-1], A[i] )
        swapped = true
      end if
    end for
  while swapped
end procedure

因此,恶意比较函数可以使两个值无限地交换进去。

但是,我能想到的所有不错的算法(quicksort,mergesort,heapsort,insertionsort)只使用for循环,所以它们的终止不应该依赖于排序例程的正确性。甚至冒泡排序本身也可以通过几次更改来保证终止(请查看wiki链接以获取示例)

所以,从实际的角度来看,不是:比较函数的正确性不应该影响排序的运行时行为*

*在最坏的情况下,像quicksort这样的模数是O(n ^ 2)...

答案 5 :(得分:0)

一旦你传递了一个不提供一致顺序的函数的排序例程,就不能保证会发生什么。人们希望C#没有什么坏处,但我从经验中知道C ++在这种情况下有一种令人不安的倾向于转移核心。