3

我一直试图弄清楚该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 个温度对象: 34、45、21 在一个ArrayList. 当我打电话时ArrayList.Sort(),该CompareTo()方法被称为喜欢34.CompareTo(45)吗?然后45.CompareTo(21)呢?返回的整数在第一次比较中为 1,在第二次比较中为 -1?如果我仅CompareTo()在 obj(参数)为 null 时才定义返回 1 的方法,那么这些整数是如何返回的?我没有定义任何返回 -1 或 0 的东西。就好像我正在实现一个已经实现的方法。CompareTo()在已经定义返回 -1、0 和 1的方法时定义它。

4

5 回答 5

9

让我们从基本思想开始。

CompareTo 的目的是什么?

42 到 1337 是多少。 42... 是否大于小于等于1337?

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

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

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

什么是“犰狳”到“十二生肖”:“犰狳”...大于小于等于“十二生肖”吗?

答案取决于您对大于、小于和等于的定义。对于字符串,通常的顺序是字典中稍后出现的单词大于较早出现的单词。

CompareTo 如何帮助排序?

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

查看数组中的两个相邻元素 A 和 B。
当 A <= 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 大于 1010 大于 20。这没有意义,结果是任何排序你do 也没有任何意义。垃圾进垃圾出。

对于三个给定的对象 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大于B,B大于C,则A大于C)。
  • 如果A.CompareTo(B)返回一个小于 0 的值,并且B.CompareTo(C)返回一个小于 0 的值,则A.CompareTo(C)返回一个小于 0 的值(如果 A 小于 B,并且 B 小于 C,则 A 小于 C)。
  • null总是小于任何非空对象。

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

于 2013-03-05T23:03:11.793 回答
0

有不同的排序算法。然而,不管有什么点,算法必须决定哪个元素更大,什么时候CompareTo被调用。

a.CompareTo(b) < 0;

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

a < b

我想你会a < b在很多伪代码或整数排序算法示例中找到这个符号。CompareTo方法IComparable<T>是一种面向对象的实现——或表示法。

于 2013-03-05T20:48:10.587 回答
0

当你想与 比较ab,你说:

int result=a.CompareTo(b);

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

然后,当您对数组进行排序时,无论使用哪种算法,您都必须将元素一起比较,将它们发送为this和发送objobject.CompareTo(或此函数的可行重载)。

于 2013-03-05T20:23:45.783 回答
0

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

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

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

于 2013-03-05T20:30:49.057 回答
0

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

element1.CompareTo(element2)

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

于 2013-03-05T20:25:22.380 回答