Array.Sort in with nontrivial comparison function

时间:2013-05-02 06:38:04

标签: c# algorithm sorting lambda

请考虑以下代码来自 C#5.0 in a Nutshell ,p。 289:

int[] numbers = { 1, 2, 3, 4, 5 };
Array.Sort (numbers, (x, y) => x % 2 == y % 2 ? 0 : x % 2 == 1 ? -1 : 1); 

,结果为{3, 5, 1, 2, 4}

我在纸上试了一下并得到了{1, 3, 5, 2, 4}

为什么计算机排序会给3 > 5 > 1

5 个答案:

答案 0 :(得分:6)

最有可能的主题是Sort不保证相等元素的顺序。与保留相等元素的原始顺序的stable sort算法不同,“不稳定排序”可以交换它们。通常,当您手动排序时,您会执行“稳定排序”版本。

Array.Sort

  

此实现执行不稳定的排序;也就是说,如果两个元素相等,则可能不会保留它们的顺序。相反,稳定的排序保留了相等元素的顺序。

样本中使用的排序函数使得1 == 3, 1 == 5因此不稳定排序允许以任何方式对这些数字进行排序,只要它们与其他数字的顺序正确:1,3,5(稳定 - 相同的顺序)如在源中)或任何序列3,1,5(不稳定排序)。

即。 OrderBy实现“稳定排序”,您可以使用相同的比较函数在以下示例中查看结果:

void Main()
{
    int[] numbers = { 1, 2, 3, 4, 5 };
    var result = numbers.OrderBy(x=> x, new MyComparer()));
      // 1, 3, 5, 2, 4
}

public class MyComparer : IComparer<int>  
{
    public int Compare( int x, int y)
    {
      return  x % 2 == y % 2 ? 0 : x % 2 == 1 ? -1 : 1;
    }
}

答案 1 :(得分:3)

虽然Array.Sort指定了

  

如果分区大小少于16个元素,则使用插入排序算法。

它没有指定它如何进行此插入排序或它使用的插入排序的风格。如前所述,它还指定了

  

此实现执行不稳定的排序

因此,返回后唯一的Array.Sort承诺关于元素的顺序是它们被排序。这适用于{3, 5, 1, 2, 4}

考虑Array.Sort使用的算法甚至可以做这样的事情(Pseudocode):

if sequence = {1, 2, 3, 4, 5} then
    sequence := {3, 5, 1, 2, 4}
end if
Sort(sequence);

当然,这是实现定义的行为,它可能会在另一个版本的.NET框架中发生变化。

修改您的代码

Array.Sort(numbers, (x, y) =>
    {
        Console.WriteLine(x + ", " + y);
        return x % 2 == y % 2 ? 0 : x % 2 == 1 ? -1 : 1;
    });

将为您提供Array.Sort

所做的比较
1, 3
1, 5
3, 5
1, 3
3, 5
2, 3
3, 4
3, 3
5, 3
5, 3
5, 5
5, 3
2, 4
2, 1
4, 2
1, 4
4, 4
4, 2
1, 2
1, 2
1, 1
1, 2
1, 1

这很可能不是你如何在纸上进行插入排序。

重点是:Array.Sort承诺对您的序列进行排序,但它不承诺 如何执行此操作。

答案 2 :(得分:2)

该代码相当于:

static void Main(string[] args)
{
    int[] numbers = { 1, 2, 3, 4, 5 };
    Array.Sort(numbers, OnComparison); 
}

private static int OnComparison(int x, int y)
{
    if (x%2 == y%2) return 0;
    if (x%2 == 1) return 1;
    return -1;
}

我明白了:

{3, 5, 1, 2, 4} 

排序操作如下:

0) {1,2,3,4,5}
1) {1,2,3,4,5}
2) {1,2,3,4,5}
3) {1,2,3,4,5}
4) {1,2,3,4,5}
5) {5,2,3,4,1}
6) {5,2,3,4,1}
7) {5,2,3,4,1}
8) {5,3,2,4,1}
9) {5,3,2,4,1}
10) {5,3,2,4,1}
11) {5,3,2,4,1}
12) {3,5,2,4,1}
13) {3,5,2,4,1}
14) {3,5,1,4,2}
15) {3,5,1,4,2}
16) {3,5,1,4,2}
17) {3,5,1,4,2}
18) {3,5,1,2,4}
19) {3,5,1,2,4}
20) {3,5,1,2,4}
21) {3,5,1,2,4}
22) {3,5,1,2,4}
23) Final: {3,5,1,2,4}

总而言之,似乎“为什么”是因为每个人都说的0问题,但我还不完全确定。

答案 3 :(得分:1)

在这里,你并没有按照顺序排列等待

试试这个:

Array.Sort(numbers, (x, y) => x % 2 == y % 2 ? x < y ? 1 : -1 : x % 2 == 1 ? -1 : 1);

答案 4 :(得分:0)

这是我理解的方式, 根据代码,您可以将其更改为:

static void Main(string[] args)
{
    int[] numbers = { 1, 2, 3, 4, 5 };
    Array.Sort(numbers, OnComparison); 
}

private static int OnComparison(int x, int y)
{
    if (x%2 == y%2) return 0;
    if (x%2 == 1) return -1;
    return 1;
}

所以arrary.sort,是在条件上排序(OnComparison,由返回值),而不是与int []数字进行比较。 所以3&amp; 5&amp; 1,均返回-1 以及array.sort的定义:

This implementation performs an unstable sort; that is, if two elements are equal, their order might not be preserved 

为什么,你得到{3,5,1,2,4}