因此,基本上,您想知道是否有任何排序算法,如果给定类似于以下内容的比较函数,则该算法不会降低其平均情况:
int Compare(object a, object b) { return Random.Next(-1,1); }
...其中Random.Next()是将在指定的下限和上限之间生成随机生成的整数的某些方法。
答案实际上是,大多数基本排序算法将根据其平均情况执行,因为它们至少满足以下两个条件之一:
- 两个唯一元素之间的比较不会在排序中进行两次,和/或
- 在排序的每个迭代中,确定至少一个元素的正确位置,以便不再对元素进行比较。
例如,SelectionSort遍历未排序元素的子列表,找到“最小”和/或“最大”元素(通过将每个元素与目前为止最大的元素进行比较),将其放置在正确的位置并重复。结果,即使使用不确定的比较器,算法在每次迭代结束时也会发现它认为是最小或最大的值,将其与要确定的位置的元素交换,而从不考虑再次该元素,因此它符合条件2。但是,在此过程中,可以多次比较A和B(作为最极端的示例,请考虑对以相反顺序排序的数组进行多次SelectionSort传递),因此它违反了条件1 。
MergeSort符合条件1,但不符合条件2;当合并子数组时,同一子数组(左侧或右侧)中的元素不会相互比较,因为已经确定数组那侧的元素彼此之间是有序的;该算法仅将每个子数组中未合并最少的元素与另一个子数组进行比较,以确定哪个较小,应该在合并列表中排在下一个。这意味着任何两个唯一的对象A和B将最多相互比较一次,但是完整的集合中任何给定元素的“最终”索引在算法完成之前是未知的。
即使InsertionSort的总体策略和复杂性看起来更像SelectionSort,它也仅服从条件1。将每个未排序的元素与已排序的元素(从大到小)进行比较,直到找到一个小于被检查元素的元素。在该点插入元素,然后考虑下一个元素。结果是,任何A和B的相对顺序都是通过一次比较确定的,并且从未进行过A和B之间的进一步比较,但是只有考虑了所有元素之后才能知道任何元素的最终位置。
QuickSort服从两者条件。在每个级别上,均选择并布置枢轴,以使“左侧”包含小于枢轴的元素,而“右侧”包含大于枢轴的元素。该级别的结果是QuickSort(左)+枢轴+ QuickSort(右),这基本上意味着枢轴元素的位置是已知的(一个索引大于左侧的长度),该枢轴从未与任何其他元素进行比较在将其选择为枢轴之后(它可能已经与以前的枢轴元素进行了比较,但是这些元素也是已知的,并且不包含在任何子数组中),并且永远不会在枢轴的相对侧出现的任何A和B比较。在纯QuickSort的大多数实现中,基本情况是一个元素,此时其当前索引是其最终索引,因此不做进一步的比较。
(2/3)N−1)。随着比较器结果的最大绝对值增加,任何一次比较返回负数或零的概率都降低到.5,从而使算法结束的可能性大大降低(99枚硬币翻转所有着陆头的可能性) ,这基本上可以归结为1.2 * 10 30中的1)
长时间编辑:有一些专门设计为“不做”的示例的“排序”,其中包含一个随机比较器。也许最著名的是BogoSort。“给出列表,如果列表顺序不正确,请随机排序列表,然后再次检查”。从理论上讲,它将最终达到正确的值排列,就像上面的“非优化的BubbleSort”一样,但是平均情况是阶乘时间(N!/ 2),并且由于生日问题(在经过足够的随机排列后,变得比唯一排列更有可能遇到重复排列的排列),这种算法永远无法完成的非零可能性是,该算法没有时间限制。