SrcForge

Lesson 37

Set

Covers creating and initializing sets, characteristics of sets, common set operations, how sets store data, and iterating through sets.

Lesson content

What is STL Set in C++?

A set is an associative container in the Standard Template Library (STL) that stores unique elements in sorted order. Unlike a vector, a set automatically removes duplicate values and keeps the elements ordered based on their comparison.

Think of a set as a guest list for an event. Each person's name appears only once, and the organizer keeps the list in alphabetical order. If someone tries to register twice, the duplicate entry is ignored.

Why does STL Set exist?

Using arrays or vectors to maintain unique, sorted data requires additional work: checking for duplicates before insertion, sorting the data after every insertion, and searching through the entire collection.

  • Preventing duplicate elements
  • Keeping elements sorted
  • Providing efficient insertion, deletion, and lookup operations

Real-world use cases

  • Removing duplicate values from data
  • Storing unique usernames or email addresses
  • Maintaining a dictionary of unique words
  • Keeping a sorted list of product IDs
  • Filtering duplicate records in databases
  • Implementing mathematical set operations

Prerequisites

  • Variables and data types
  • Arrays and loops
  • Functions
  • Templates (recommended)
  • Basic STL containers such as vector

Including the set header

#include <set>

Creating a set

set<data_type> set_name;

// Example:
set<int> numbers;

// This creates an empty set of integers.

Initializing a set

  • set<int> s; – empty set
  • set<int> s = {1,2,3}; – initialize with values
  • set<int> s{5,10,15}; – uniform initialization

Duplicate values are automatically removed.

set<int> s = {5, 2, 8, 5, 2, 1};

// Stored values:
// 1 2 5 8

Characteristics of STL Set

  • Duplicate elements: not allowed
  • Order: automatically sorted
  • Random access: not supported
  • Search: fast (O(log n))
  • Insertion: fast (O(log n))
  • Deletion: fast (O(log n))

Common set operations

  • insert() – add an element
  • erase() – remove an element
  • find() – search for an element
  • count() – check if an element exists
  • size() – number of elements
  • empty() – check if the set is empty
  • clear() – remove all elements
  • begin() – iterator to first element
  • end() – iterator to one past the last element

How sets store data

Unlike vectors, sets are not stored in contiguous memory. Most C++ implementations use a self-balancing binary search tree (commonly a Red-Black Tree), which keeps elements sorted and provides efficient operations.

Iterating through a set

You can use a range-based for loop or iterators.

for (int value : numbers)
{
    cout << value << " ";
}

Example 1: Creating and displaying a set

#include <iostream>
#include <set>
using namespace std;

int main()
{
    set<int> numbers;

    numbers.insert(30);
    numbers.insert(10);
    numbers.insert(20);
    numbers.insert(10);

    for (int num : numbers)
    {
        cout << num << " ";
    }

    return 0;
}

// Output: 10 20 30

Example 2: Searching for an element

#include <iostream>
#include <set>
using namespace std;

int main()
{
    set<int> marks = {75, 80, 90};

    if (marks.find(80) != marks.end())
    {
        cout << "80 Found";
    }
    else
    {
        cout << "80 Not Found";
    }

    return 0;
}

Example 3: Erasing elements

#include <iostream>
#include <set>
using namespace std;

int main()
{
    set<int> values = {1,2,3,4,5};

    values.erase(3);

    for(int value : values)
    {
        cout << value << " ";
    }

    return 0;
}

// Output: 1 2 4 5

Example 4: Counting unique words

#include <iostream>
#include <set>
#include <string>
using namespace std;

int main()
{
    set<string> words;

    words.insert("Apple");
    words.insert("Banana");
    words.insert("Apple");
    words.insert("Orange");

    cout << "Unique Words: ";

    for(const string& word : words)
    {
        cout << word << " ";
    }

    return 0;
}

// Output: Unique Words: Apple Banana Orange

Example 5: Student registration system

#include <iostream>
#include <set>
#include <string>
using namespace std;

int main()
{
    set<string> students;

    students.insert("Alice");
    students.insert("Bob");
    students.insert("Charlie");
    students.insert("Alice");

    cout << "Registered Students:\n";

    for(const string& name : students)
    {
        cout << name << endl;
    }

    cout << "\nTotal Students: ";
    cout << students.size();

    return 0;
}

Common mistakes and pitfalls

  • Expecting duplicates to be stored. Fix: remember that sets automatically remove duplicates
  • Trying to access elements using an index (s[0]). Fix: use iterators or a range-based for loop
  • Assuming insertion order is preserved. Fix: elements are always sorted according to the comparison function
  • Modifying elements directly through an iterator. Fix: elements in a set are immutable; erase and insert a new value instead
  • Using a set when duplicate values are required. Fix: use std::multiset if duplicates should be allowed

Best practices

  • Use a set whenever uniqueness is required
  • Prefer find() over manually searching through the container
  • Use count() when you only need to check whether an element exists
  • Use range-based for loops for cleaner iteration
  • Use const references when iterating over large objects
  • Choose std::unordered_set if sorting is unnecessary and average constant-time lookups are preferred
  • Avoid unnecessary copying of sets; pass them by const reference to functions

When not to use this

  • Duplicate values must be stored (use std::multiset)
  • Fast random access by index is required (use std::vector)
  • Insertion order must be preserved (consider std::vector or std::list)
  • You require average constant-time lookups without sorted order (use std::unordered_set)
  • Memory usage is a primary concern, as tree-based structures generally consume more memory than vectors

Summary

  • STL Set in C++ stores unique elements in sorted order
  • Duplicate values are automatically ignored
  • Common operations such as insertion, deletion, and search typically run in O(log n) time
  • Sets do not support random access using indexes
  • Use insert(), erase(), find(), count(), size(), and clear() to manage elements
  • Range-based for loops provide a simple way to iterate over a set
  • Choose a set when uniqueness and automatic sorting are important
  • Consider std::unordered_set for faster average lookups when sorting is not required

Frequently asked questions

What is the difference between a set and a vector?

A vector stores elements in insertion order and allows duplicates. A set stores only unique elements and automatically keeps them sorted.

Can a set store duplicate values?

No. A set automatically removes duplicate values. If duplicates are needed, use std::multiset.

Why can't I access set elements using an index?

A set is implemented as a tree-based associative container rather than a contiguous array, so it does not support index-based access.

What is the time complexity of searching in a set?

Searching with find() is typically O(log n) because most implementations use a self-balancing binary search tree.

When should I use std::unordered_set instead of std::set?

Use std::unordered_set when you don't need sorted elements and want faster average-case insertion, deletion, and lookup (typically O(1)). Use std::set when maintaining sorted order is important.