Possible implementation of Thomas Cammeyer answer
I found Thomas's approach very smart and useful - as some of us dream of code, and I find the actual implementation a bit complicated, I would like to provide some ready-to-use code.
The solution presented here is as general as possible:
- Assumptions about the type of container or range are not allowed, except that their iterators must meet the requirements of ValueSwappable and RandomAccessIterator (due to partial sorting with
nth_element ) - You can use any type of number - the required features are described below
Another improvement that I believe is that the condition without breaking can be checked at an early stage: since we must scan the minimum one way or another, we can also scan the maximum at the same time, and then determine if whether the range of numbers even a space is worth finding.
And last but not least, the same recursive approach can be adapted for sorted ranges! If you encode the template values ββin the parameter whether the range is already sorted, you can simply skip the partial sorting plus make the definition of the minimum / maximum elements no-op.
#include <type_traits> #include <iterator> #include <tuple> #include <utility> #include <algorithm> #include <cstddef> // number type must be: // * arithmetic // * subtractable (a - b) // * divisible by 2 (a / 2) // * incrementable (++a) // * less-than-comparable (a < b) // * default-constructible (A{}) // * copy-constructible // * value-constructible (A(n)) // * unsigned or number range must only contain values >0 /** Find lowest gap value in a range */ template<typename Range> typename std::remove_reference_t<Range>::value_type lowest_gap_value_unsorted(Range&& r) { static_assert(!std::is_lvalue_reference_v<Range> && !std::is_const_v<Range>, "lowest_gap_value_unsorted requires a modifiable copy of the passed range"); return lowest_gap_value_unsorted(std::begin(r), std::end(r), std::size(r)); } /** Find lowest gap value in a range with specified size */ template<typename Range> typename std::remove_reference_t<Range>::value_type lowest_gap_value_unsorted(Range&& r, std::size_t N) { static_assert(!std::is_lvalue_reference_v<Range> && !std::is_const_v<Range>, "lowest_gap_value_unsorted requires a modifiable copy of the passed range"); return lowest_gap_value_unsorted(std::begin(r), std::end(r), N); } /** Find lowest gap value in an iterator range */ template<typename Iterator> typename std::iterator_traits<Iterator>::value_type lowest_gap_value_unsorted(Iterator first, Iterator last) { return lowest_gap_value_unsorted(first, last, std::distance(first, last)); } /** Find lowest gap value in an iterator range with specified size */ template<typename Iterator> typename std::iterator_traits<Iterator>::value_type lowest_gap_value(Iterator first, Iterator last, std::size_t N) { typedef typename std::iterator_traits<Iterator>::value_type Number; if (bool empty = last == first) return increment(Number{}); Iterator minElem, maxElem; std::tie(minElem, maxElem) = std::minmax_element(first, last); if (bool contains0 = !(Number{} < *minElem)) throw std::logic_error("Number range must not contain 0"); if (bool missing1st = increment(Number{}) < *minElem) return increment(Number{}); if (bool containsNoGap = !(Number(N) < increment(*maxElem - *minElem))) return increment(*maxElem); return lowest_gap_value_unsorted_recursive(first, last, N, *minElem); } template<typename Iterator> typename std::iterator_traits<Iterator>::value_type lowest_gap_value_unsorted_recursive(Iterator first, Iterator last, std::size_t N, typename std::iterator_traits<Iterator>::value_type minValue) { typedef typename std::iterator_traits<Iterator>::value_type Number; if (N == 1) return ++minValue; if (N == 2) { // determine greater of the 2 remaining elements Number maxValue = !(minValue < *first) ? *std::next(first) : *first; if (bool gap = ++minValue < maxValue) return minValue; else return ++maxValue; } Iterator medianElem = std::next(first, N / 2); // sort partially std::nth_element(first, medianElem, last); if (bool gapInLowerHalf = (Number(N) / 2 < *medianElem - minValue)) return lowest_gap_value_unsorted_recursive(first, medianElem, N / 2, minValue); else return lowest_gap_value_unsorted_recursive(medianElem, last, N / 2 + N % 2, *medianElem); }; template<typename T> T increment(T v) { return ++v; }