Internal working of the Sort() and CompareTo() met

2019-02-25 08:16发布

I've been trying to figure out how the CompareTo() method works internally and I failed. I've searched this site and read some posts, and I think I've seen all there is to see in MSDN about this subject and I just don't seem to get it. An MSDN example:

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");
    }
}

This is the MSDN example of the implementation of the CompareTo() method. I understand this, I understand how the IComparable interface works, if I understood correctly this gets called when I use the ArrayList.Sort() method.

What I don't understand is: when does the program pass the argument for the CompareTo(object obj) method? Or in other words, how does the Sort() method work? I mean, this code is comparing the instance of a temperature with another instance of temperature, but when or how is the program getting the second temperature instance for the comparison to take place? I hope my question makes sense.

I've tried printing to the screen the CompareTo() process so maybe I could reverse-engineer the output but I confused myself even more.

EDIT: Maybe if I go step by step I can explain myself better. Suppose I have 3 temperatures objects: 34, 45, 21 in an ArrayList. When I call ArrayList.Sort(), is the CompareTo() method called like 34.CompareTo(45)? And then 45.CompareTo(21)? The returned integers would be 1 in the first comparison and -1 in the second? And how did those integers get returned if I only defined the CompareTo() method to return 1 only if the obj (the parameter) was null? I didn't define anything to return -1 or 0. It's as if I was implementing a method that's already been implemented. Defining a CompareTo() method when it's already defined to return -1, 0 and 1.

5条回答
仙女界的扛把子
2楼-- · 2019-02-25 08:31

The sorting method is independent of the CompareTo method. I'm not sure what sorting algorithm is used but I'd guess it's something like a quick sort (obv not a bubble sort). If you're interested in those algorithms Wikipedia documents them in detail.

The CompareTo method is simply a means to compare objects of the same type. It's defined for many of the common .NET types to begin with and can be overriden to do comparisons between custom objects (things you create). Basically you call it from an object of type A passing it a second object of type A and the return value indicates if the two are equal or if one is greater than the other.

It's best to think of CompareTo as a utility function. It exists so you can do custom comparisons using the sorting methods provided with common .NET data structures. Without something like it, you would have to write the sorting algorithm yourself in order to compare types that you've created. It's purpose is simply to make sorting methods reusable/extensible.

查看更多
虎瘦雄心在
3楼-- · 2019-02-25 08:37

There are different sort algorithms. However, no matter what there are points where an algorithm must decide which element is greater, which is when CompareTo is called.

a.CompareTo(b) < 0;

If a and b are Integers (or in pseudocode), you could also use:

a < b

I think you will find the a < b notation in a lot of pseudocode or integer sort algorithm examples. CompareTo method of IComparable<T> is an object-oriented implementation - or notation.

查看更多
smile是对你的礼貌
4楼-- · 2019-02-25 08:39

When you want to compare a to b, you say:

int result=a.CompareTo(b);

ie, the first comparison operand is this and the second one is the parameter passed to the function.

Then when you sort the array, regardless of the algorithm used you have to compare elements together, sending them as this and obj to object.CompareTo (or viable overloads of this function).

查看更多
▲ chillily
5楼-- · 2019-02-25 08:40

Let's start with the basic idea.

What is the purpose of CompareTo?

What is 42 to 1337. Is 42... greater than, less than or equal to 1337?

This question and its answer are modeled by the CompareTo method in the IComparable<T> and IComparable interfaces. For A.CompareTo(B), the method can return:

  • A is greater than B: an integer value greater than 0.
  • A is less than B: an integer value less than 0.
  • A is equal to B: an integer value equal to 0.

And of course, IComparable is not limited to integers. You can implement IComparable to compare any two objects that you think should be comparable. For example, strings:

What is "Armadillo" to "Zodiac": Is "Armadillo"... greater than, less than or equal to "Zodiac"?

The answer depends on your definition of greater than, less than and equal to. For strings the usual order is that a word that would occur later in the dictionary is greater than a word that occurs earlier.

How does CompareTo help sorting?

Okay, now you know how you can compare any two objects. This is useful for many algorithms, but mostly sorting and ordering algorithms. Take for example a very simple sorting algorithm: stupid sort. The idea is:

Look at two adjacent elements in your array, A and B.
When A <= B: go forward to the next pair.
When A > B: swap A and B, and go back to the previous pair.
When we reach the end, we're done.

You see, to get sorted there must be a way to determine which of the two elements is the greater one. That's where IComparable<T> comes into play.

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--;
        }
    }
}

What happens when CompareTo would always return 1?

You can of course program CompareTo to return anything you want. But if you screw up, then your method no longer answers the question what is this to obj? Always returning a 1 would mean that for any A and B, A is always greater than B. That's like saying: 20 is greater than 10 and 10 is greater than 20. It does not make sense, and the result is that any sorting you do will also not make any sense. Garbage in... garbage out.

The rules of the game are, for three given objects A, B and C:

  • A.CompareTo(A) must return 0 (A is equal to A).
  • If A.CompareTo(B) returns 0, then B.CompareTo(A) returns 0 (If A is equal to B, then B is equal to A).
  • If A.CompareTo(B) returns 0, and B.CompareTo(C) returns 0, then A.CompareTo(C) returns 0 (If A is equal to B, and B is equal to C, then A is equal to C).
  • If A.CompareTo(B) returns a value greater than 0, then B.CompareTo(A) returns a value less than 0 (If A is greater than B, then B is less than A).
  • If A.CompareTo(B) returns a value less than 0, then B.CompareTo(A) returns a value greater than 0 (If A is less than B, then B is greater than A).
  • If A.CompareTo(B) returns a value greater than 0, and B.CompareTo(C) returns a value greater than 0, then A.CompareTo(C) returns a value greater than 0 (If A is greater than B, and B is greater than C, then A is greater than C).
  • If A.CompareTo(B) returns a value less than 0, and B.CompareTo(C) returns a value less than 0, then A.CompareTo(C) returns a value less than 0 (If A is less than B, and B is less than C, then A is less than C).
  • null is always less than any non-null object.

If your implementation doesn't adhere to these (simple and logical) principles, then sorting algorithms can literally do anything, and probably don't give the results you expect.

查看更多
▲ chillily
6楼-- · 2019-02-25 08:53

In short, Sort takes two elements of your ArrayList, and calls CompareTo for the first elements, and pass second element as an argument, like this:

element1.CompareTo(element2)

CompareTo returns negative value if element1 is less that element2, 0 if they are equal, positive value otherwise. Sort uses this return value to, uhm, do some sorting. Then it repeats this process for next two elements, does some more sorting, and so on until ArrayList is sorted. Search for "sorting algorithm" to get more info about this process.

查看更多
登录 后发表回答