Sort()和CompareTo()方法的内部工作
我一直试图弄清楚CompareTo()
方法如何在内部工作,但我失败了。 我搜索了这个网站并阅读了一些post,我想我已经看到了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()
过程,所以也许我可以对输出进行逆向工程,但我更加困惑自己。
编辑 :也许如果我一步一步走,我可以更好地解释自己。 假设我在ArrayList
有3个温度对象: ArrayList
。 当我调用ArrayList.Sort()
, CompareTo()
方法是否被称为34.CompareTo(45)
? 然后45.CompareTo(21)
? 返回的整数在第一次比较中为1,在第二次比较中为-1? 如果我只定义了CompareTo()
方法只在obj(参数)为null时才返回1,那么这些整数是如何返回的呢? 我没有定义任何返回-1或0的东西。就好像我正在实现一个已经实现的方法。 定义一个CompareTo()
方法,当它已被定义为返回-1,0和1时。
让我们从基本想法开始。
CompareTo的目的是什么?
什么是42到1337.是42 … 大于 , 小于或等于 1337?
这个问题及其答案由IComparable
和IComparable
接口中的CompareTo
方法建模。 对于A.CompareTo(B)
,该方法可以返回:
- A 大于 B:大于0的整数值。
- A 小于 B:小于0的整数值。
- A 等于 B:等于0的整数值。
当然, IComparable
并不仅限于整数。 您可以实现IComparable
来比较您认为应该具有可比性的任何两个对象。 例如,字符串:
什么是“犰狳”到“十二生肖”:“犰狳”是…… 大于 , 小于或等于 “十二生肖”?
答案取决于你的定义大于,小于等于。 对于字符串,通常的顺序是字典中稍后出现的单词大于先前出现的单词。
CompareTo如何帮助排序?
好的,现在您知道如何比较任何两个对象了。 这对许多算法很有用,但主要是排序和排序算法。 以一个非常简单的排序算法为例: 愚蠢的排序 。 这个想法是:
查看数组中的两个相邻元素A和B.
当A <= B时:前进到下一对。
当A> B:交换A和B时,返回上一对。
当我们到达终点时,我们已经完成了。
你看,为了得到排序,必须有一种方法来确定两个元素中的哪一个是更大的元素。 这就是IComparable
发挥作用的地方。
public static void StupidSort(T[] array) where T : IComparable { 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
来返回你想要的任何东西。 但如果你搞砸了,那么你的方法不再回答这个问题是什么? 总是返回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大于B,并且B大于C,则A大于C )。 - 如果
A.CompareTo(B)
返回小于0的值,并且B.CompareTo(C)
返回小于0的值,则A.CompareTo(C)
返回小于0的值( 如果A小于B,并且B小于C,则A小于C )。 -
null
始终小于任何非null对象。
如果您的实现不遵循这些(简单和逻辑)原则,那么排序算法可以完全做任何事情,并且可能不会给出您期望的结果。
当你想比较a
到b
,你会说:
int result=a.CompareTo(b);
即,第一个比较操作数是this
,第二个是传递给函数的参数。
然后,当您对数组进行排序时,无论使用何种算法,您都必须将元素进行比较,将它们作为this
和obj
发送到object.CompareTo
(或此函数的可行重载)。
排序方法独立于CompareTo
方法。 我不确定使用了什么排序算法,但我猜它类似于快速排序(事实上不是冒泡排序)。 如果您对这些算法感兴趣,维基百科会详细记录它们。
CompareTo
方法只是一种比较相同类型对象的方法。 它是为许多常见的.NET类型定义的,可以覆盖它们来自定义对象(你创建的东西)之间的比较。 基本上你从A类型的对象中调用它,传递第二个A类型的对象,返回值表示两者是否相等或者一个是否大于另一个。
最好将CompareTo
视为实用function。 它存在,因此您可以使用常见.NET数据结构提供的排序方法进行自定义比较。 如果没有这样的东西,你必须自己编写排序算法,以便比较你创建的类型。 它的目的只是使排序方法可重用/可扩展。
简而言之,Sort接受ArrayList的两个元素,并为第一个元素调用CompareTo,并将第二个元素作为参数传递,如下所示:
element1.CompareTo(element2)
如果element1小于element2,则CompareTo返回负值,如果它们相等则返回0,否则返回正值。 Sort使用此返回值,嗯,做一些排序。 然后它为下两个元素重复此过程,进行更多排序,依此类推,直到对ArrayList进行排序。 搜索“排序算法”以获取有关此过程的更多信息。
有不同的排序算法。 但是,无论什么算法必须决定哪个元素更大,哪个是在调用CompareTo
时。
a.CompareTo(b) < 0;
如果a和b是Integers
(或伪代码),您还可以使用:
a < b
我想你会在很多伪代码或整数排序算法例子中找到a < b
表示法。 IComparable
CompareTo
方法是面向对象的实现 - 或表示法。