Cpp Libs Set
# C++ Standard Library: `` Container
The `` header in the C++ Standard Template Library (STL) provides an associative container that stores unique elements following a specific order.
A `std::set` is highly efficient for searching, inserting, and removing elements. Under the hood, it is typically implemented as a **Red-Black Tree** (a self-balancing binary search tree), which guarantees logarithmic time complexity $O(\log n)$ for these operations.
---
## Key Characteristics of `std::set`
* **Unique Elements:** Duplicate values are not allowed. If you attempt to insert an existing value, the insertion is ignored.
* **Ordered Storage:** Elements are automatically sorted in ascending order by default using the `<` operator of the element type.
* **Immutable Keys:** Once an element is added to a set, its value cannot be modified directly (iterators are constant). To change an element, you must remove it and insert the new value.
* **Requirements on Element Types:**
* The element type must be **comparable** (it must support strict weak ordering, typically via the `<` operator or a custom comparator).
* The element type must be **copyable** and **assignable**.
---
## Syntax and Initialization
To use `std::set`, you must include the `` header:
```cpp
#include
```
### Declaration Syntax
```cpp
std::set containerName;
```
### Common Initialization Methods
```cpp
// 1. Empty set of integers
std::set mySet;
// 2. Initializer list (C++11 and later)
std::set mySet2 = {10, 40, 20, 30}; // Automatically sorted to: 10, 20, 30, 40
// 3. Custom sorting order (descending)
std::set> descendingSet = {10, 40, 20, 30}; // Sorted to: 40, 30, 20, 10
```
---
## Common Member Functions
| Member Function | Description | Time Complexity |
| :--- | :--- | :--- |
| `insert(val)` | Inserts an element into the set if it is not already present. | $O(\log n)$ |
| `erase(val)` | Removes the element with the specified value. | $O(\log n)$ |
| `erase(iterator)` | Removes the element at the specified iterator position. | Amortized $O(1)$ |
| `find(val)` | Returns an iterator to the element if found; otherwise, returns `end()`. | $O(\log n)$ |
| `count(val)` | Returns `1` if the element exists, and `0` otherwise (since elements are unique). | $O(\log n)$ |
| `size()` | Returns the number of elements in the set. | $O(1)$ |
| `empty()` | Returns `true` if the set is empty, `false` otherwise. | $O(1)$ |
| `clear()` | Removes all elements from the set. | $O(n)$ |
---
## Practical Code Example
The following complete example demonstrates how to declare a set, insert elements, search for values, delete elements, and iterate through the container.
```cpp
#include
#include
int main() {
// Declare a set of integers
std::set mySet;
// 1. Insert elements (note that 20 is inserted twice)
mySet.insert(10);
mySet.insert(40);
mySet.insert(20);
mySet.insert(30);
mySet.insert(20); // Duplicate element, will be ignored
// 2. Output the elements of the set
// Notice that the output is automatically sorted and contains no duplicates
std::cout << "Set contains: ";
for (int num : mySet) {
std::cout << num << " ";
}
std::cout << std::endl;
// 3. Find an element
int searchKey = 20;
if (mySet.find(searchKey) != mySet.end()) {
std::cout << searchKey << " is in the set." << std::endl;
} else {
std::cout << searchKey << " is not in the set." << std::endl;
}
// 4. Erase an element
mySet.erase(20);
std::cout << "After erasing 20, set contains: ";
for (int num : mySet) {
std::cout << num << " ";
}
std::cout << std::endl;
// 5. Check if the set is empty
if (mySet.empty()) {
std::cout << "The set is empty." << std::endl;
} else {
std::cout << "The set is not empty." << std::endl;
}
// 6. Get the size of the set
std::cout << "The set contains " << mySet.size() << " elements." << std::endl;
return 0;
}
```
### Output
```text
Set contains: 10 20 30 40
20 is in the set.
After erasing 20, set contains: 10 30 40
The set is not empty.
The set contains 3 elements.
```
---
## Advanced Considerations
### 1. Performance vs. `std::unordered_set`
* Use `std::set` when you need your elements to remain **sorted** or when you need to perform range queries (e.g., finding all elements between $A$ and $B$ using `lower_bound` and `upper_bound`).
* If sorting is not required and you only need fast lookups, insertions, and deletions, consider using `std::unordered_set` (implemented via a hash table), which offers average $O(1)$ time complexity.
### 2. Custom Comparators for User-Defined Types
If you want to store custom objects (like a `struct` or `class`) in a `std::set`, you must either overload the `<` operator or provide a custom comparator struct.
```cpp
#include
#include
#include
struct Person {
std::string name;
int age;
// Overload the < operator to sort by age
bool operator<(const Person& other) const {
return age < other.age;
}
};
int main() {
std::set people = { {"Alice", 30}, {"Bob", 25} };
// Sorted automatically by age: Bob (25) then Alice (30)
for (const auto& p : people) {
std::cout << p.name << " (" << p.age << ")\n";
}
return 0;
}
```
---
## Summary
The `` container is an essential tool in the C++ Standard Library. It is ideal for scenarios requiring unique collection management, automatic sorting, and fast logarithmic-time lookups. By understanding its underlying Red-Black Tree structure and API, you can write highly optimized and clean C++ code.
YouTip