我知道4.5的排序算法从4.0改变了,但我怀疑内省排序的实现有问题。 似乎在反向排序列表的情况下行为不正常,当有人期望与“已排序”情况(如4.0中)相同数量的比较时,该数字奇怪地非常大。
.net 4 x64
随机25514058,分类20525265,反向20525285
.net 4.5 x64
随机22112103,排序16935357,逆转 31148728 !!
我用来获得比较次数的代码(使用4.0和4.5编译)是:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace sortTest {
class Program {
class CmpCount : IComparer<int> {
private int _count;
/// <summary>
///
/// </summary>
public int Count {
get {
return _count;
}
}
public int Compare( int x, int y ) {
_count++;
return x.CompareTo( y );
}
}
static void Main( string[] args ) {
Random rnd = new Random(1234);
List<int> list = new List<int>();
for ( int i = 0; i < 1000000; i++ ) {
list.Add( rnd.Next() );
}
CmpCount cmp = new CmpCount();
list.Sort( cmp );
int random = cmp.Count;
cmp = new CmpCount();
list.Sort( cmp );
int sorted = cmp.Count;
cmp = new CmpCount();
list.Reverse();
list.Sort( cmp );
int reversed = cmp.Count;
Console.WriteLine("random {0}, sorted {1}, reversed {2}",random,sorted,reversed);
}
}
}
编辑:我正在调试源代码,似乎从未调用过HeapSort。也许它需要一个特殊的制作输入,这将触发它。实际上在上述情况下,4.5排序实际上只是快速排序。
快速查看源代码似乎4.0快速排序更复杂,而4.5是一个差(直接来自书籍?)实现。
如果我理解正确的话,4.5似乎也盲目地偏爱已排序的列表。这可能是反向排序列表的问题
答案 0 :(得分:2)
introsort的.NET 4.5实现首先尝试执行Quicksort。当它看到递归深度超出特定点时,它会停止Quicksort并以Heap排序重新开始。
因此,期望进行大量比较并不是不合理的,因为算法正在进行部分排序,然后重新启动以进行完整排序。
此外,没有人知道.NET Quicksort如何选择要进行分区的项目。可能它使用的是中位数3.但它是否随机选择三个?第一,中,最后?对于两种相同的数组,分区可能不同(因此比较的数量可能不同)。
无论如何,Introsort并不声称自己是完美的。该算法很可能会检测到潜在的最坏情况,并切换到堆排序,即使使用快速排序会更快。 Introsort避免了最坏情况的行为,但有时可能表现出非最佳行为。
此外,无法保证您排序的阵列是相同的。您确定.NET 4和.NET 4.5之间的Random
类实现没有改变吗? Random(1234)
可能会在4.5上创建与4.0上不同的序列。如果是这样的话,你就不会比较同一阵列上的排序。