In this section, we are going to play with std::sort and std::partial_sort:
- First, we include all that's necessary and declare that we use the std namespace:
#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <random>
using namespace std;
- We will print the state of a vector of integers multiple times, so let's abbreviate this task by writing a small procedure:
static void print(const vector<int> &v)
{
copy(begin(v), end(v), ostream_iterator<int>{cout, ", "});
cout << 'n';
}
- We begin with a vector that contains some example numbers:
int main()
{
vector<int> v {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
- Because we will shuffle the vector multiple times in order to play with different sort functions, we need a random number generator:
random_device rd;
mt19937 g {rd()};
- The std::is_sorted function tells us if the content of a container is sorted. This line should print 1:
cout << is_sorted(begin(v), end(v)) << 'n';
- With std::shuffle, we shake around the content of the vector in order to sort it again later. The first two arguments denote the range that will be shuffled and the third argument is the random number generator:
shuffle(begin(v), end(v), g);
- The is_sorted function should now return false so that 0 is printed, and the values in the vector should be the same but in a different order. We will see after we have printed both again to the shell:
cout << is_sorted(begin(v), end(v)) << 'n';
print(v);
- Now, we reestablish the original item ordering by using std::sort. The same prints to the terminal should now again give us the sorted ordering from the beginning:
sort(begin(v), end(v));
cout << is_sorted(begin(v), end(v)) << 'n';
print(v);
- Another interesting function is std::partition. Maybe, we do not want to fully sort the list because it is sufficient to just have the items that are smaller than some value at the front. So, let's partition the vector in order to move all the items that are smaller than 5 to the front and print it:
shuffle(begin(v), end(v), g);
partition(begin(v), end(v), [] (int i) { return i < 5; });
print(v);
- The next sort-related function is std::partial_sort. We can use it to sort the content of a container, but only to some extent. It will put the N smallest of all vector elements in the first half of the vector in a sorted order. The rest will reside in the second half, which will not be sorted:
shuffle(begin(v), end(v), g);
auto middle (next(begin(v), int(v.size()) / 2));
partial_sort(begin(v), middle, end(v));
print(v);
- What if we want to sort a data structure that has no comparison operator? Let's define one and make a vector of such items:
struct mystruct {
int a;
int b;
};
vector<mystruct> mv {{5, 100}, {1, 50}, {-123, 1000},
{3, 70}, {-10, 20}};
- The std::sort function optionally accepts a comparison function as its third argument. Let's use that and provide it with such a function. Just to show that this is possible, we compare them by their second field, b. This way, they will appear in the order of mystruct::b and not mystruct::a:
sort(begin(mv), end(mv),
[] (const mystruct &lhs, const mystruct &rhs) {
return lhs.b < rhs.b;
});
- The last step is printing the sorted vector of mystruct items:
for (const auto &[a, b] : mv) {
cout << "{" << a << ", " << b << "} ";
}
cout << 'n';
}- Let's compile and run our program.
The first 1 results from the std::is_sorted call after initializing the sorted vector. Then, we shuffled the vector and got a 0 from the second is_sorted call. The third line shows all the vector items after the shuffling. The next 1 is the result of the is_sorted call after sorting it again with std::sort.
Then, we shuffled the whole vector again and partitioned it using std::partition. We can see that all the items that are less than 5 are also to the left of 5 in the vector. All items that are greater than 5 are to its right. Apart from that, they seem shuffled.
The second last line shows the result of std::partial_sort. All items up to the middle appear strictly sorted but the rest do not.
In the last line, we can see our vector of mystruct instances. They are strictly sorted by their second member values:
$ ./sorting_containers
1
0
7, 1, 4, 6, 8, 9, 5, 2, 3, 10,
1
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1, 2, 4, 3, 5, 7, 8, 10, 9, 6,
1, 2, 3, 4, 5, 9, 8, 10, 7, 6,
{-10, 20} {1, 50} {3, 70} {5, 100} {-123, 1000}