C++ | Sorting
Sorting and sequence containers
Section titled “Sorting and sequence containers”std::sort, found in the standard library header algorithm, is a standard library algorithm for sorting a range of values, defined by a pair of iterators. std::sort takes as the last parameter a functor used to compare two values; this is how it determines the order. Note that std::sort is not stable.
The comparison function must impose a Strict, Weak Ordering on the elements. A simple less-than (or greater-than) comparison will suffice.
A container with random-access iterators can be sorted using the std::sort algorithm:
#include <vector>#include <algorithm>
std::vector<int> MyVector = {3, 1, 2}
//Default comparison of <std::sort(MyVector.begin(), MyVector.end());std::sort requires that its iterators are random access iterators. The sequence containers std::list and std::forward_list (requiring C++11) do not provide random access iterators, so they cannot be used with std::sort. However, they do have sort member functions which implement a sorting algorithm that works with their own iterator types.
#include <list>#include <algorithm>
std::list<int> MyList = {3, 1, 2}
//Default comparison of <//Whole list only.MyList.sort();Their member sort functions always sort the entire list, so they cannot sort a sub-range of elements. However, since list and forward_list have fast splicing operations, you could extract the elements to be sorted from the list, sort them, then stuff them back where they were quite efficiently like this:
void sort_sublist(std::list<int>& mylist, std::list<int>::const_iterator start, std::list<int>::const_iterator end) { //extract and sort half-open sub range denoted by start and end iterator std::list<int> tmp; tmp.splice(tmp.begin(), list, start, end); tmp.sort(); //re-insert range at the point we extracted it from list.splice(end, tmp);}Sorting sequence containers with specifed ordering
Section titled “Sorting sequence containers with specifed ordering”If the values in a container have certain operators already overloaded, std::sort can be used with specialized functors to sort in either ascending or descending order:
#include <vector>#include <algorithm>#include <functional>
std::vector<int> v = {5,1,2,4,3};
//sort in ascending order (1,2,3,4,5)std::sort(v.begin(), v.end(), std::less<int>());
// Or just:std::sort(v.begin(), v.end());
//sort in descending order (5,4,3,2,1)std::sort(v.begin(), v.end(), std::greater<int>());
//Or just:std::sort(v.rbegin(), v.rend());In C++14, we don’t need to provide the template argument for the comparison function objects and instead let the object deduce based on what it gets passed in:
std::sort(v.begin(), v.end(), std::less<>()); // ascending orderstd::sort(v.begin(), v.end(), std::greater<>()); // descending orderSorting sequence containers by overloaded less operator
Section titled “Sorting sequence containers by overloaded less operator”If no ordering function is passed, std::sort will order the elements by calling operator< on pairs of elements, which must return a type contextually convertible to bool (or just bool). Basic types (integers, floats, pointers etc) have already build in comparison operators.
We can overload this operator to make the default sort call work on user-defined types.
// Include sequence containers#include <vector>#include <deque>#include <list>
// Insert sorting algorithm#include <algorithm>
class Base { public:
// Constructor that set variable to the value of v Base(int v): variable(v) { }
// Use variable to provide total order operator less //`this` always represents the left-hand side of the compare. bool operator<(const Base &b) const { return this->variable < b.variable; }
int variable;};
int main() { std::vector <Base> vector; std::deque <Base> deque; std::list <Base> list;
// Create 2 elements to sort Base a(10); Base b(5);
// Insert them into backs of containers vector.push_back(a); vector.push_back(b);
deque.push_back(a); deque.push_back(b);
list.push_back(a); list.push_back(b);
// Now sort data using operator<(const Base &b) function std::sort(vector.begin(), vector.end()); std::sort(deque.begin(), deque.end()); // List must be sorted differently due to its design list.sort();
return 0;}Sorting sequence containers using compare function
Section titled “Sorting sequence containers using compare function”// Include sequence containers#include <vector>#include <deque>#include <list>
// Insert sorting algorithm#include <algorithm>
class Base { public:
// Constructor that set variable to the value of v Base(int v): variable(v) { }
int variable;};
bool compare(const Base &a, const Base &b) { return a.variable < b.variable;}
int main() { std::vector <Base> vector; std::deque <Base> deque; std::list <Base> list;
// Create 2 elements to sort Base a(10); Base b(5);
// Insert them into backs of containers vector.push_back(a); vector.push_back(b);
deque.push_back(a); deque.push_back(b);
list.push_back(a); list.push_back(b);
// Now sort data using comparing function std::sort(vector.begin(), vector.end(), compare); std::sort(deque.begin(), deque.end(), compare); list.sort(compare);
return 0;}Sorting sequence containers using lambda expressions (C++11)
Section titled “Sorting sequence containers using lambda expressions (C++11)”// Include sequence containers#include <vector>#include <deque>#include <list>#include <array>#include <forward_list>
// Include sorting algorithm#include <algorithm>
class Base { public:
// Constructor that set variable to the value of v Base(int v): variable(v) { }
int variable;};
int main() { // Create 2 elements to sort Base a(10); Base b(5);
// We're using C++11, so let's use initializer lists to insert items. std::vector <Base> vector = {a, b}; std::deque <Base> deque = {a, b}; std::list <Base> list = {a, b}; std::array <Base, 2> array = {a, b}; std::forward_list<Base> flist = {a, b};
// We can sort data using an inline lambda expression std::sort(std::begin(vector), std::end(vector), [](const Base &a, const Base &b) { return a.variable < b.variable;});
// We can also pass a lambda object as the comparator // and reuse the lambda multiple times auto compare = [](const Base &a, const Base &b) { return a.variable < b.variable;}; std::sort(std::begin(deque), std::end(deque), compare); std::sort(std::begin(array), std::end(array), compare); list.sort(compare); flist.sort(compare);
return 0;}sorting with std::map (ascending and descending)
Section titled “sorting with std::map (ascending and descending)”This example sorts elements in ascending order of a key using a map.
You can use any type, including class, instead of std::string, in the example below.
#include <iostream>#include <utility>#include <map>
int main(){ std::map<double, std::string> sorted_map; // Sort the names of the planets according to their size sorted_map.insert(std::make_pair(0.3829, "Mercury")); sorted_map.insert(std::make_pair(0.9499, "Venus")); sorted_map.insert(std::make_pair(1, "Earth")); sorted_map.insert(std::make_pair(0.532, "Mars")); sorted_map.insert(std::make_pair(10.97, "Jupiter")); sorted_map.insert(std::make_pair(9.14, "Saturn")); sorted_map.insert(std::make_pair(3.981, "Uranus")); sorted_map.insert(std::make_pair(3.865, "Neptune"));
for (auto const& entry: sorted_map) { std::cout << entry.second << " (" << entry.first << " of Earth's radius)" << '\n'; }}Output:
Mercury (0.3829 of Earth's radius)Mars (0.532 of Earth's radius)Venus (0.9499 of Earth's radius)Earth (1 of Earth's radius)Neptune (3.865 of Earth's radius)Uranus (3.981 of Earth's radius)Saturn (9.14 of Earth's radius)Jupiter (10.97 of Earth's radius)If entries with equal keys are possible, use multimap instead of map (like in the following example).
To sort elements in descending manner, declare the map with a proper comparison functor (std::greater<>):
#include <iostream>#include <utility>#include <map>
int main(){ std::multimap<int, std::string, std::greater<int>> sorted_map; // Sort the names of animals in descending order of the number of legs sorted_map.insert(std::make_pair(6, "bug")); sorted_map.insert(std::make_pair(4, "cat")); sorted_map.insert(std::make_pair(100, "centipede")); sorted_map.insert(std::make_pair(2, "chicken")); sorted_map.insert(std::make_pair(0, "fish")); sorted_map.insert(std::make_pair(4, "horse")); sorted_map.insert(std::make_pair(8, "spider"));
for (auto const& entry: sorted_map) { std::cout << entry.second << " (has " << entry.first << " legs)" << '\n'; }}Output
centipede (has 100 legs)spider (has 8 legs)bug (has 6 legs)cat (has 4 legs)horse (has 4 legs)chicken (has 2 legs)fish (has 0 legs)Sorting built-in arrays
Section titled “Sorting built-in arrays”The sort algorithm sorts a sequence defined by two iterators. This is enough to sort a built-in (also known as c-style) array.
int arr1[] = {36, 24, 42, 60, 59};
// sort numbers in ascending ordersort(std::begin(arr1), std::end(arr1));
// sort numbers in descending ordersort(std::begin(arr1), std::end(arr1), std::greater<int>());Prior to C++11, end of array had to be “calculated” using the size of the array:
// Use a hard-coded number for array sizesort(arr1, arr1 + 5);
// Alternatively, use an expressionconst size_t arr1_size = sizeof(arr1) / sizeof(*arr1);sort(arr1, arr1 + arr1_size);Remarks
Section titled “Remarks”The std::sort function family is found in the algorithm library.