Sort()和CompareTo()方法的内部工作

时间:2013-03-05 20:15:52

标签: c# sorting compareto icomparable

我一直试图弄清楚CompareTo()方法如何在内部工作,但我失败了。我搜索了这个网站并阅读了一些帖子,我想我已经看到了MSDN中有关这个主题的所有内容,我似乎并没有得到它。一个MSDN示例:

public int CompareTo(object obj)
{
    if (obj == null)
    {
        return 1;
    }

    Temperature otherTemperature = obj as Temperature;
    if (otherTemperature != null)
    {
        return this.temperatureC.CompareTo(otherTemperature.temperatureC);
    }
    else
    {
        throw new ArgumentException("the object is not a temperature");
    }
}

这是CompareTo()方法实现的MSDN示例。我理解这一点,我理解IComparable接口是如何工作的,如果我理解正确的话,当我使用ArrayList.Sort()方法时会调用它。

我不明白的是:程序何时传递CompareTo(object obj)方法的参数?或者换句话说,Sort()方法如何工作?我的意思是,这段代码将温度的实例与另一个温度实例进行比较,但是程序何时或如何获得第二个温度实例进行比较?我希望我的问题有道理。

我已经尝试在屏幕上打印CompareTo()进程,所以也许我可以对输出进行反向工程,但我更加困惑了自己。

修改: 也许如果我一步一步走,我可以更好地解释自己。假设我有3个温度对象:ArrayList中的34,45,21。当我致电ArrayList.Sort()时,调用的CompareTo()方法是34.CompareTo(45)吗?然后45.CompareTo(21)?返回的整数在第一次比较中为1,在第二次比较中为-1?如果我只定义了CompareTo()方法,只有当obj(参数)为空时返回1,那么这些整数是如何返回的?我没有定义任何返回-1或0的东西。就好像我正在实现一个已经实现的方法。定义CompareTo()方法时,已定义为返回-1,0和1。

5 个答案:

答案 0 :(得分:8)

让我们从基本想法开始。

CompareTo的目的是什么?

  

什么是42到1337.是42 ... 大于小于等于 1337?

此问题及其答案由CompareToIComparable<T>接口中的IComparable方法建模。对于A.CompareTo(B),该方法可以返回:

  • A 大于 B:大于0的整数值。
  • A 小于 B:小于0的整数值。
  • A 等于 B:整数值等于0.

当然,IComparable并不仅限于整数。您可以实现IComparable来比较您认为应该具有可比性的任何两个对象。例如,字符串:

  

什么是“Armadillo”到“Zodiac”:“Armadillo”是...... 大于小于等于“星座“?

答案取决于你对大于,小于等于的定义。对于字符串,通常的顺序是字典中以后出现的单词大于之前发生的单词。

CompareTo如何帮助排序?

好的,现在您知道如何比较任何两个对象了。这对许多算法很有用,但主要是排序和排序算法。以一个非常简单的排序算法为例:愚蠢的排序。这个想法是:

  

查看数组中的两个相邻元素A和B.   当A&lt; = B:前进到下一对。
  当A> B:交换A和B,然后返回上一对   当我们到达终点时,我们已经完成了。

你看,为了得到排序,必须有一种方法来确定两个元素中哪一个是更大的元素。这就是IComparable<T>发挥作用的地方。

public static void StupidSort<T>(T[] array)
            where T : IComparable<T>
{
    int index = 0;
    while (index < array.Length)
    {
        if (index == 0 ||
            array[index - 1].CompareTo(array[index]) <= 0)
        {
            index++;
        }
        else
        {
            Swap(array, index - 1, index);
            index--;
        }
    }
}

当CompareTo总是返回1时会发生什么?

您当然可以编程CompareTo以返回您想要的任何内容。但是,如果你搞砸了,那么你的方法不再回答问题 thisobj是什么?总是返回1意味着对于任何A和B,A是总是大于B.这就像说:20大于10 10大于20.它没有意义,结果是你做的任何排序也没有任何意义。垃圾......垃圾出来。

对于三个给定的对象A,B和C,游戏规则是:

  • A.CompareTo(A)必须返回0( A等于A )。
  • 如果A.CompareTo(B)返回0,则B.CompareTo(A)返回0(如果A等于B,则B等于A )。
  • 如果A.CompareTo(B)返回0,B.CompareTo(C)返回0,则A.CompareTo(C)返回0(如果A等于B,B等于C,则A是等于C )。
  • 如果A.CompareTo(B)返回大于0的值,则B.CompareTo(A)返回小于0的值(如果A大于B,则B小于A
  • 如果A.CompareTo(B)返回小于0的值,则B.CompareTo(A)返回大于0的值(如果A小于B,则B大于A
  • 如果A.CompareTo(B)返回大于0的值,B.CompareTo(C)返回大于0的值,则A.CompareTo(C)返回大于0的值(如果A大于0 B和B大于C,则A大于C
  • 如果A.CompareTo(B)返回小于0的值,B.CompareTo(C)返回小于0的值,则A.CompareTo(C)返回小于0的值(如果A小于0) B和B小于C,则A小于C
  • null总是小于任何非空对象。

如果您的实现不符合这些(简单和逻辑)原则,那么排序算法可以完全做任何事情,并且可能不会给出您期望的结果。

答案 1 :(得分:0)

如果您想将ab进行比较,请说:

int result=a.CompareTo(b);

即,第一个比较操作数是this,第二个是传递给函数的参数。

然后,当您对数组进行排序时,无论使用何种算法,您都必须将元素进行比较,将它们作为thisobj发送到object.CompareTo(或此函数的可行重载)

答案 2 :(得分:0)

简而言之,Sort接受ArrayList的两个元素,并为第一个元素调用CompareTo,并将第二个元素作为参数传递,如下所示:

element1.CompareTo(element2)

如果element1小于element2,则CompareTo返回负值,如果它们相等则返回0,否则返回正值。 Sort使用此返回值,嗯,做一些排序。然后它为下两个元素重复此过程,进行更多排序,依此类推,直到对ArrayList进行排序。搜索“排序算法”以获取有关此过程的更多信息。

答案 3 :(得分:0)

排序方法独立于CompareTo方法。我不确定使用什么排序算法,但我猜它类似于快速排序(事实上不是冒泡排序)。如果您对这些算法感兴趣,维基百科会详细记录它们。

CompareTo方法只是比较相同类型对象的一种方法。它是为许多常见的.NET类型定义的,可以覆盖它们来自定义对象(你创建的东西)之间的比较。基本上你从A类型的对象中调用它,传递第二个A类型的对象,返回值表示两者是否相等或者是否大于另一个。

最好将CompareTo视为效用函数。它存在,因此您可以使用常见.NET数据结构提供的排序方法进行自定义比较。如果没有这样的东西,你必须自己编写排序算法,以便比较你创建的类型。它的目的只是使排序方法可重用/可扩展。

答案 4 :(得分:0)

有不同的排序算法。但是,无论什么算法必须决定哪个元素更大,哪个是调用CompareTo

a.CompareTo(b) < 0;

如果a和b为Integers(或伪代码),您还可以使用:

a < b

我想你会在很多伪代码或整数排序算法的例子中找到a < b符号。 CompareTo的{​​{1}}方法是面向对象的实现 - 或符号。