std::unordered_set


STL Container: std::unordered_set

std::unordered_set is a container in C++ that stores unique elements in no particular order. Unlike std::set, which is ordered, std::unordered_set is implemented using a hash table, which allows for average-case constant-time complexity (O(1)) for insertions, deletions, and lookups. This makes std::unordered_set particularly useful when order is not important, but fast access and uniqueness of elements are required.

Key Characteristics of std::unordered_set

Custom Hash Functions:

You can define custom hash functions and equality functions if the default ones are not suitable for your needs.

Basic Operations on std::unordered_set

Example 1: Basic Usage of std::unordered_set

include <iostream>
include <unordered_set>

int main() {
    std::unordered_set<int> mySet = {1, 2, 3, 4, 5};

    // Insertion
    mySet.insert(6);
    mySet.insert(3);  // Duplicate element, will not be inserted

    // Lookup
    if (mySet.find(3) != mySet.end()) {
        std::cout << "3 is in the set." << std::endl;
    }

    // Deletion
    mySet.erase(2);

    // Iterating over the set
    std::cout << "Elements in mySet: ";
    for (int elem : mySet) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    return 0;
}

Explanation:

Example 2: Custom Hash Function

You can define a custom hash function for more complex types, such as custom classes or structures.

include <iostream>
include <unordered_set>
include <string>

struct Person {
    std::string name;
    int age;

    bool operator==(const Person& other) const {
        return name == other.name && age == other.age;
    }
};

// Custom hash function for Person
struct PersonHash {
    std::size_t operator()(const Person& p) const {
        return std::hash<std::string>()(p.name) ^ std::hash<int>()(p.age);
    }
};

int main() {
    std::unordered_set<Person, PersonHash> people = {
        {"Alice", 30},
        {"Bob", 25},
        {"Charlie", 40}
    };

    // Insertion
    people.insert({"Dave", 35});

    // Lookup
    Person searchPerson = {"Bob", 25};
    if (people.find(searchPerson) != people.end()) {
        std::cout << "Found Bob, age 25." << std::endl;
    }

    // Iterating over the set
    std::cout << "People in the set:" << std::endl;
    for (const auto& person : people) {
        std::cout << person.name << ", " << person.age << std::endl;
    }

    return 0;
}

Explanation:

Example 3: Handling Collisions

In hash tables, collisions can occur when two different elements produce the same hash value. std::unordered_set handles collisions internally using chaining or open addressing, ensuring that the elements are still accessible. However, when defining a custom hash function, it's crucial to ensure that the hash distribution is as uniform as possible to minimize collisions.

include <iostream>
include <unordered_set>

int main() {
    // A custom hash function that could cause many collisions
    struct BadHash {
        std::size_t operator()(int x) const {
            return x % 10;  // Not a very good hash function
        }
    };

    std::unordered_set<int, BadHash> mySet = {10, 20, 30, 40, 50};

    mySet.insert(11);  // Likely to collide with 10

    std::cout << "Elements in mySet: ";
    for (int elem : mySet) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    return 0;
}

Explanation:

Performance Considerations

When to Use std::unordered_set

Summary

std::unordered_set is a powerful tool in C++ when you need a high-performance set with no concern for element order. It combines the advantages of sets with the efficiency of hash tables, making it suitable for many applications where quick access to unique elements is required.

Previous Page | Course Schedule | Course Content