我注意到在使用自定义IComparer<T>
在.NET中对数组进行排序时,会请求将项目与自身进行比较。
为什么会这样?当然,看看是否要对相同的索引进行比较并假设结果必须为零,这是一个微不足道的优化?
示例代码:
class Comparer : IComparer<string>
{
public int Compare(string x, string y)
{
Console.WriteLine("{0} vs {1}", x, y);
return string.Compare(x, y);
}
}
static void Main(string[] args)
{
var values = new[] {"A", "D", "C", "B", "E"};
Array.Sort(values, new Comparer());
}
输出(标记奇怪的比较):
A vs C
A vs E
C vs E
A vs C
D vs C
C vs E
C vs B
C vs C ***
C vs C ***
A vs B
A vs B
A vs A ***
A vs B
A vs A ***
D vs E
D vs E
D vs D ***
D vs E
D vs D ***
答案 0 :(得分:3)
人们报告不同的结果,因为Array.Sort()算法已多次更改。至少在.NET 4.0和.NET 4.5中,可能在此之前。最新最好的版本从QuickSort切换到Introsort。
由于针对Quicksort非常糟糕的最坏情况行为O(n ^ 2)的反措施,您看到一个元素本身进行了比较。 Wikipedia article for Introsort解释得很好:
在快速排序中,其中一项关键操作是选择枢轴:分区列表所围绕的元素。最简单的数据透视选择算法是将列表的第一个或最后一个元素作为数据透视,导致排序或接近排序的输入情况不良。 Niklaus Wirth的变体使用中间元素来防止这些事件发生,为人为序列退化为O(n²)。 3的中间枢轴选择算法采用列表的第一个,中间和最后一个元素的中位数;然而,即使这在许多真实世界的输入上表现良好,仍然可以设计一个3中位数的杀手名单,这将导致基于这种枢轴选择技术的快速排序的急剧减速。此类输入可能会被攻击者利用,例如通过将此类列表发送到Internet服务器进行排序作为拒绝服务攻击。
您正在看到3个中间轴选择算法的副作用。