Initialize Multi-Set with Custom Comparator in C++
In this article, we will learn how to initialize a std::multiset with a custom comparator in C++. A multiset is similar to a set, except that it allows duplicate elements. It stores elements in a sorted order based on a comparison function.
By default, elements are compared using the < (less-than) operator. However, with a custom comparator, we can define how elements should be compared. For example, if we define a custom comparator that sorts elements in descending order and insert the following elements into the multiset:
Input: 3 12 5 8 1 7 9 4 6 Output: {12, 9, 8, 7, 6, 5, 4, 3, 1}
We will explain how to implement and use a custom comparator in C++ to change the default sorting behavior, with an example to illustrate the process.
Initializing a Multiset with a Custom Comparator
To initialize a multiset with a custom comparator, we need to define a custom function or functor that specifies how elements should be compared. This comparator is then passed as a parameter to the multiset to control the sorting order.
Let's look at three common ways to define a custom comparator:
Using a Function Pointer
In this approach, we define a custom function that compares two elements and returns true if one should be ordered before the other. This function is then passed to the std::multiset constructor to control the sorting order.
Example
In this example, we create a function (customComparator) that sorts elements in descending order. The function is passed to the multiset constructor, which uses it to store and order the elements accordingly.
#include <iostream> #include <set> #include <functional> using namespace std; // Comparator function to compare elements in descending order bool customComparator(int a, int b) { return a > b; // Elements will be sorted in descending order } int main() { // Initialize multiset with a custom comparator multiset<int, function<bool(int, int)>> myMultiset(customComparator); // Insert elements myMultiset.insert(10); myMultiset.insert(30); myMultiset.insert(20); myMultiset.insert(40); // Display elements in sorted order cout << "After inserting elements: " << endl; for (auto element : myMultiset) { cout << element << " "; } cout << endl; return 0; }
Below is the output that shows the elements displayed in descending order:
After inserting elements: 40 30 20 10
Time Complexity: Complexity:O(n log n), with each of the n insertions taking O(log n) due to the balanced tree structure.
Space Complexity: O(n), as the multiset stores n elements.
Using a Function Object (Functor)
In this approach, we define a class (functor) that overloads the () operator to implement the custom comparison logic. This functor is then passed to the std::multiset constructor to control the ordering of the elements
Example
In this example, we use a functor (CustomComparator) to compare elements in descending order. The functor is passed to the std::multiset constructor to control the ordering of elements.
#include <iostream> #include <set> using namespace std; // Functor class to compare elements in descending order class CustomComparator { public: bool operator()(int a, int b) const { return a > b; // Elements will be sorted in descending order } }; int main() { // Initialize multiset with a custom comparator (using functor) multiset<int, CustomComparator> myMultiset; // Insert elements myMultiset.insert(10); myMultiset.insert(30); myMultiset.insert(20); myMultiset.insert(40); // Display elements in sorted order cout << "After inserting elements: " << endl; for (auto element : myMultiset) { cout << element << " "; } return 0; }
The output below shows the elements ordered in descending order:
After inserting elements: 40 30 20 10
Time Complexity: O(n log n) due to n insertions, each taking O(log n), and O(n) for iteration.
Space Complexity: O(n) because the multiset stores n elements.
Using a Lambda Expression
In this approach, we use a lambda expression to define a custom comparator inline. A lambda expression is an anonymous function that allows us to specify the comparison logic directly when initializing the multiset.
Example
In this example, we define a lambda function(comparator) that compares two integers in descending order. We then use this lambda as a custom comparator to initialize the multiset. The elements are then inserted and displayed in sorted order.
#include <iostream> #include <set> #include <functional> int main() { // Using lambda as a comparator auto comp = [](const int& a, const int& b) { return a > b; }; std::multiset<int, decltype(comp)> myMultiset(comp); // Add elements myMultiset.insert({10, 30, 20, 40}); // Print the elements std::cout << "After inserting elements: "<< std::endl ; for (const auto& elem : myMultiset) { std::cout << elem << " "; } return 0; }
Below is the output showing the elements displayed in descending order:
After inserting elements: 40 30 20 10
Time Complexity: O(n log n) due to n insertions, each taking O(log n), and O(n) for iteration.
Space Complexity: O(n) because the multiset stores n elements.
Conclusion
In this article, we explained how to initialize a std::multiset with a custom comparator using three methods: function pointer, functor, and lambda expression. Each method allows us to define how the elements should be sorted based on our needs.