【问题标题】:Fastest way to sort an array in descending order按降序对数组进行排序的最快方法
【发布时间】:2011-10-14 02:24:27
【问题描述】:

为什么是下面的代码

Array.Sort(values);
Array.Reverse(values);

相较于

,按降序对数组进行排序要快得多
Array.Sort(values, (a,b)=>(-a.CompareTo(b)));

代码在调试器之外以发布模式运行。

为数组生成降序排序的最有效方法是什么,最好是单行?

【问题讨论】:

  • 把匿名方法换成普通方法能重现吗?
  • 您是否尝试过使用不调用旧比较器的非匿名自定义比较器?差异有多大?您是否也遵循了以下类似的教程,考虑了微基准测试yoda.arachsys.com/csharp/benchmark.html?因为要做好是一件相当困难的事情。

标签: c# sorting


【解决方案1】:

这是一个很好的问题。我敢打赌你的 values 数组是一个原始类型的数组!

这里确实是那种占主导地位的排序,因为Reverse的复杂度是O(n),而排序是O(n logn)。

问题是,在对原始类型进行排序时,.NET 实际上调用了一个本地函数,这非常快——比使用比较或比较器快得多。

函数调用TrySZSort:

[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[SecurityCritical]
[MethodImpl(MethodImplOptions.InternalCall)]
private static bool TrySZSort(Array keys, Array items, int left, int right);

下面是它在 Array 类中的调用方式:

[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[SecuritySafeCritical]
public static void Sort<T>(T[] array, int index, int length, IComparer<T> comparer)
{
  if (array == null)
    throw new ArgumentNullException("array");
  else if (index < 0 || length < 0)
    throw new ArgumentOutOfRangeException(length < 0 ? "length" : "index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  else if (array.Length - index < length)
    throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
  else if (length > 1 && (comparer != null && comparer != Comparer<T>.Default || !Array.TrySZSort((Array) array, (Array) null, index, index + length - 1)))
    ArraySortHelper<T>.Default.Sort(array, index, length, comparer);
}

【讨论】:

  • 微软提供的源代码甚至在没有指定比较器的情况下得到注释TrySZSort is still faster than the generic implementation. The reason is Int32.CompareTo is still expensive than just using '&lt;' or '&gt;'. :D
  • 还提供Comparison&lt;T&gt; 而不是IComparer&lt;T&gt; 强制框架进行包装,因为内部实现使用了一个比较器......再一层间接(快速但每次比较都会执行)
【解决方案2】:

作为link points out

这里的排序方法总是以内部 TrySZSort 或 QuickSort 结束 当它不抛出异常时的方法。 TrySZSort 内部 方法针对一维数组进行了优化,也称为“零” 数组或向量

因为基类库中使用的 TrySZSort 方法是 在本机代码中实现,它已经过大量优化。所以, 这种方法可能比用 C# 编写的任何解决方案都快 语言

【讨论】:

  • 不说原因就说法拉利比 Moris Minor 快,这不是一个真正的答案。
【解决方案3】:

代表。

对委托的调用比对IComparable.CompareTo的默认调用慢得多

更新:

如果您想要相同(或接近)的速度,请实现 IComparer 接口并将其传递给 sort 方法。

http://msdn.microsoft.com/en-us/library/bzw8611x

【讨论】:

    【解决方案4】:

    因为在您的第二个版本中,它必须在每次进行比较时调用您的(匿名)函数,然后在其中调用 .CompareTo,因此您有两个间接,否则它可以使用内置比较(对于原始类型)。

    基本上,您需要支付函数调用开销,我敢打赌,在执行此类操作时,原生原始类型会消除这些开销。尽管在技术上是可行的(我认为),但我怀疑 Jitter 是否能够在您的第二种情况下完全内联它们。

    【讨论】:

      猜你喜欢
      • 2012-07-15
      • 2011-07-22
      • 2014-02-16
      • 1970-01-01
      • 2013-09-20
      • 1970-01-01
      • 2021-11-15
      • 2011-02-09
      • 2021-12-28
      相关资源
      最近更新 更多