Determining if an unordered vectorT has all unique elements
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Determining whether all elements in a vector are unique is a classic problem in C++ programming. It comes up in data validation, deduplication checks, and as a subroutine in larger algorithms. Because std::vector does not enforce uniqueness (unlike std::set), you need an explicit check when uniqueness is a requirement.
This article covers three practical approaches with working code, analyzes their time and space tradeoffs, and highlights pitfalls to watch for with custom types.
Approach 1: Sort and Compare Adjacent Elements
Sorting the vector brings duplicates next to each other. After sorting, a single linear pass with std::adjacent_find detects any duplicate pair.
Time complexity: O(n log n) for the sort, plus O(n) for the linear scan. Space complexity: O(n) because we copy the vector. If you can modify the original, pass by reference and the extra space drops to O(1) (ignoring the sort's internal stack usage).
This is a good default choice when you do not want to pull in additional headers and the vector is not enormous.
Approach 2: Insert into a Set
A std::unordered_set provides average O(1) lookups. Insert each element, and if any insertion fails (meaning the element already exists), you have a duplicate.
Time complexity: O(n) on average. Space complexity: O(n) for the set.
This approach has the advantage of short-circuiting: it returns as soon as the first duplicate is found, which can be much faster than sorting when duplicates appear early in the vector.
Approach 3: Brute Force (Nested Loop)
For very small vectors, a simple nested loop avoids any overhead from sorting or hashing.
Time complexity: O(n^2). Space complexity: O(1).
This is only practical for vectors with fewer than a few hundred elements. Beyond that, the quadratic time becomes unacceptable.
One-Liner with std::set Size Comparison
If conciseness matters more than early termination, you can compare the size of a set constructed from the vector to the vector's size.
This is clean and readable, but it always processes every element (no short-circuiting) and uses std::set which has O(n log n) insertion cost. For a quick check in non-performance-critical code, it works well.
Handling Custom Types
For the set-based approaches to work with custom types, those types must satisfy certain requirements:
std::unordered_set<T>requires a hash function andoperator==. For standard types, these are provided. For custom structs, you need to specializestd::hash<T>or provide a custom hasher.std::set<T>requiresoperator<(or a custom comparator).- The sort-based approach requires
operator<.
Common Pitfalls
- Floating-point equality. Comparing floating-point numbers with
==is unreliable due to precision errors. For vectors ofdoubleorfloat, consider rounding to a fixed number of decimal places or using an epsilon-based comparison, which means the set-based approach will not work directly. - Accidentally modifying the original vector. The sort-based approach modifies the vector in place. If you need the original order preserved, work on a copy.
- Poor hash functions for custom types. A bad hash function that produces many collisions will degrade the unordered_set approach from O(n) to O(n^2) in the worst case. Test your hash distribution if performance matters.
- Empty and single-element vectors. An empty vector and a vector with one element are trivially unique. Make sure your function handles these edge cases correctly (all approaches above do).
Summary
For most use cases, the unordered_set approach offers the best combination of O(n) average time and early termination on duplicates. The sort-then-scan method is a solid alternative when you want to avoid the overhead of hashing. The brute-force approach is fine for small vectors where simplicity matters most. When working with custom types, make sure to provide the required equality, comparison, or hash operators before reaching for any of these techniques.

