--- id: sorting title: "Sorting" author: Siyong (WIP) order: 3 prerequisites: - - Silver - Containers ---
Description: Todo
- Sorting - Comparators (C++) - Coordinate Compression **Sorting** is exactly what it sounds like: arranging items in some particular order. ## Sorting Algorithms There are many sorting algorithms, here are some sources to learn about the popular ones: - [Bubble Sort](https://www.freecodecamp.org/news/bubble-sort/) - [Quicksort](https://medium.com/karuna-sehgal/a-quick-explanation-of-quick-sort-7d8e2563629b) - [Mergesort](https://www.geeksforgeeks.org/merge-sort/) (why are these important?) ## Library Sorting - [C++ - std::sort](https://en.cppreference.com/w/cpp/algorithm/sort) - Java: [Arrays.sort documentation](https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#sort(java.lang.Object[])) - Python: [sorted documentation](https://docs.python.org/3/howto/sorting.html) Problems: - [Counting Haybales (Easy)](http://www.usaco.org/index.php?page=viewproblem2&cpid=666) ## Custom Comparators (mention in context of http://www.usaco.org/index.php?page=viewproblem2&cpid=992) *Custom comparators* define how the elements are ordered. This section is very language-specific and will be separated by language. ### C++ Side note: In C++, a comparator must return false for two identical objects (not doing so results in undefined behavior and potentially RTE) #### Comparators for Sorting There are 2 main ways to have a custom comparator in c++ Type 1) Overloading operator - Pro: - This is the easiest to implement - Easy to work with STL - Con: - Only works for objects (not primitives) - Only supports two types of comparisons (less than (<) and greater than (>)) ```cpp struct Foo { int Bar; Foo(int _Bar=-1):Bar(_Bar){} bool operator < (const Foo& foo2) const {return Bar < foo2.Bar;} }; const int N = 8; int main() { Foo a[N]; for(int i=0;i ```cpp struct Foo { int Bar; Foo(int _Bar=-1):Bar(_Bar){} }; const int N = 8; Foo a[N]; bool cmp1(Foo foo1, Foo foo2) {return foo1.Bar < foo2.Bar;} auto cmp2 = [](Foo foo1, Foo foo2) {return foo1.Bar < foo2.Bar;};//requires c++11 or above int main() { printf("--- Method 1 ---\n"); for(int i=0;i Set(cmp);//pass the comparator as a parameter priority_queue, decltype(cmp)> pq(cmp); //Side Note: priority queue is sorted in REVERSE order (largest elements are first) map Map(cmp); ``` #### Example of Comparators for Primitives Since you cannot overload operators for primitives, you must use custom comparators ```cpp const int N = 8; int a[N], b[N] = {4,8,2,3,4,1,2,4}; int main() { printf("--- Comparator 1 ---\n"); iota(a, a+N, 0); sort(a, a+N, greater()); //sort a in decreasing order for(int i=0;iy);}); //sort a by increasing values of b[i], breaking ties by decreasing index for(int i=0;i ```py class Foo: def __init__(self, _Bar): self.Bar = _Bar def __str__(self): return "Foo({})".format(self.Bar) def __lt__(self, o): # lt means less than return self.Bar < o.Bar a = [] for i in range(8): a.append(Foo(random.randint(1, 10))) print(*a) print(*sorted(a)) ``` Output: ``` Foo(0) Foo(1) Foo(2) Foo(1) Foo(9) Foo(5) Foo(5) Foo(8) Foo(0) Foo(1) Foo(1) Foo(2) Foo(5) Foo(5) Foo(8) Foo(9) ``` Type 2) Function/Lambda - This method defines how to compare two elements represented by an integer - Positive: First term is greater than the second term - Zero: First term and second term are equal - Negative: First term is less than the second term ```py from functools import cmp_to_key class Foo: def __init__(self, _Bar): self.Bar = _Bar def __str__(self): return "Foo({})".format(self.Bar) a = [] for i in range(8): a.append(Foo(random.randint(0, 9))) print(*a) print(*sorted(a, key=cmp_to_key(lambda foo1, foo2: foo1.Bar - foo2.Bar))) def cmp(foo1, foo2): return foo1.Bar - foo2.Bar print(*sorted(a, key=cmp_to_key(cmp))) ``` Output: ``` Foo(0) Foo(1) Foo(2) Foo(1) Foo(9) Foo(5) Foo(5) Foo(8) Foo(0) Foo(1) Foo(1) Foo(2) Foo(5) Foo(5) Foo(8) Foo(9) Foo(0) Foo(1) Foo(1) Foo(2) Foo(5) Foo(5) Foo(8) Foo(9) ``` Type 3) Remapping Key - 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`. ```py class Foo: def __init__(self, _Bar, _Baz): self.Bar,self.Baz = _Bar,_Baz def __str__(self): return "Foo({},{})".format(self.Bar, self.Baz) a = [] for i in range(8): a.append(Foo(random.randint(1, 9)*10, random.randint(1, 9))) print(*a) print(*sorted(a, key=lambda foo: foo.Bar+foo.Baz)) def key(foo): return foo.Bar + foo.Baz print(*sorted(a, key=key)) ``` Output: ``` Foo(10,2) Foo(30,2) Foo(60,6) Foo(90,7) Foo(80,7) Foo(80,9) Foo(60,9) Foo(90,8) Foo(10,2) Foo(30,2) Foo(60,6) Foo(60,9) Foo(80,7) Foo(80,9) Foo(90,7) Foo(90,8) Foo(10,2) Foo(30,2) Foo(60,6) Foo(60,9) Foo(80,7) Foo(80,9) Foo(90,7) Foo(90,8) ``` ## Coordinate Compression - CPH 3 - coord compress