description: Both Java and C++ have built-in functions for sorting. However, if we use custom objects, or if we want to sort elements in a different order, then we'll need to use a custom comparator.
new Problem("Silver", "Lifeguards", "786", "Easy", false, [], "sort endpoints of intervals"),
new Problem("Silver", "Rental Service", "787", "Easy", false, [], ""),
new Problem("Silver", "Mountains", "896", "Easy", false, [], ""),
new Problem("Silver", "Mooyo Mooyo", "860", "Easy", false, [], "Not a sorting problem, but you can use sorting to simulate gravity. - Write a custom comparator which puts zeroes at the front and use `stable_sort` to keep the relative order of other elements the same."),
new Problem("Silver", "Meetings", "967", "Very Hard", false, [], ""),
Normally, sorting functions rely on moving objects with a lower value in front of objects with a higher value if sorting in ascending order, and vice versa if in descending order. This is done through comparing two objects at a time.
- If object $x$ is less than object $y$, return `true`
- If object $x$ is greater than or equal to object $y$, return `false`
Essentially, the comparator determines whether object $x$ belongs to the left of object $y$ in a sorted ordering. A comparator **must** return false for two identical objects (not doing so results in undefined behavior and potentially RTE).
In addition to returning the correct answer, comparators should also satisfy the following conditions:
- The function must be consistent with respect to reversing the order of the arguments: if $x \neq y$ and `compare(x, y)`is positive, then `compare(y, x)` should be negative and vice versa
- The function must be transitive. If `compare(x, y)` is true and `compare(y, z)` is true, then `compare(x, z)` should also be true. If the first two compare functions both return `false`, the third must also return `false`.
A generic way of implementing a custom comparator is to define a function. For our example, we'll use a `struct` of a Person that contains a person's height and weight, and sort in ascending order by height. A `struct` is essentially a user-defined data structure:
Let's say we have an array `Person arr[N]`. To sort the array, we need to make custom comparator which will be a function, and then pass the function as a parameter into the build-in sort function:
If we instead wanted to sort in descending order, this is also very simple. Instead of the `cmp` function returning `return a.height < b.height;`, it should do `return a.height > b.height;`.
In addition to returning the correct number, comparators should also satisfy the following conditions:
- The function must be consistent with respect to reversing the order of the arguments: if $compare(x, y)$ is positive, then $compare(y, x)$ should be negative and vice versa.
- The function must be transitive. If $compare(x, y) > 0$ and $compare(y, z) > 0$, then $compare(x, z) > 0$. Same applies if the compare functions return negative numbers.
- Equality must be consistent. If $compare(x, y) = 0$, then $compare(x, z)$ and $compare(y, z)$ must both be positive, both negative, or both zero. Note that they don't have to be equal, they just need to have the same sign.
Java has default functions for comparing `int`, `long`, `double` types. The `Integer.compare()`, `Long.compare()`, and `Double.compare()` functions take two arguments $x$ and $y$ and compare them as described above.
Now, there are two ways of implementing this in Java: `Comparable`, and `Comparator`. They essentially serve the same purpose, but `Comparable` is generally easier and shorter to code. `Comparable` is a function implemented within the class containing the custom object, while `Comparator` is its own class. For our example, we'll use a `Person` class that contains a person's height and weight, and sort in ascending order by height.
If we use `Comparable`, we'll need to put `implements Comparable<Person>` into the heading of the class. Furthermore, we'll need to implement the `compareTo` method. Essentially, `compareTo(x)` is the `compare` function that we described above, with the object itself as the first argument, or `compare(self, x)`.
```java
static class Person implements Comparable<Person>{
When using `Comparator`, the syntax for using the built-in sorting function requires a second argument: `Arrays.sort(arr, new Comp())`, or `Collections.sort(list, new Comp())`.
If we instead wanted to sort in descending order, this is also very simple. Instead of the comparing function returning `Integer.compare(x, y)` of the arguments, it should instead return `-Integer.compare(x, y)`.
- This method maps an object to another comparable datatype with which to be sorted. In this case, `Foo` is sorted by the sum of its members `x` and `y`.
Now, suppose we wanted to sort a list of `Person`s in ascending order, primarily by height and secondarily by weight. We can do this quite similarly to how we handled sorting by one criterion earlier. What the comparator function needs to do is to compare the weights if the heights are equal, and otherwise compare heights, as that's the primary sorting criterion.
### C++
```cpp
bool cmp(Person a, Person b) {
if(a.height == b.height) {
return a.weight < b.weight;
}
return a.height < b.height;
}
int main() {
sort(arr, arr+N, cmp); // sorts the array in ascending order by height and then weight if the heights are equal
}
```
Sorting with an arbitrary number of criteria is done similarly.
### Java
```java
static class Person implements Comparable<Person>{
int height, weight;
public Person(int h, int w){
height = h; weight = w;
}
public int compareTo(Person p){
if(height == p.height){
return Integer.compare(weight, p.weight);
} else {
return Integer.compare(height, p.height);
}
}
}
```
Sorting with an arbitrary number of criteria is done similarly.
An alternative way of representing custom objects is with arrays. Instead of using a custom object to store data about each person, we can simply use `int[]`, where each `int` array is of size 2, and stores pairs of {height, weight}, probably in the form of a list like `ArrayList<int[]>`. Since arrays aren't objects in the usual sense, we need to use `Comparator`. Example for sorting by the same two criteria as above:
```java
static class Comp implements Comparator<int[]>{
public int compare(int[] a, int[] b){
if(a[0] == b[0]){
return Integer.compare(a[1], b[1]);
} else {
return Integer.compare(a[0], b[0]);
}
}
}
```
I don't recommend using arrays to represent objects mostly because it's confusing, but it's worth noting that some competitors do this.