Für jeden Bereich, erinnern Sie sich an den "aktuellen" Wert (von der ersten bis zur letzten mit der Schrittgröße). Fügen Sie das zusammen mit dem Bereich in eine Prioritätswarteschlange ein, sortiert nach dem aktuellen Wert.
Nimm die Spitze heraus, wenn ihr aktueller Wert sich von der letzten unterscheidet, dann benutze sie. Fügen Sie dann den nächsten Schritt ein, wenn es einen anderen gibt.
Vorausgesetzt, dass die Schrittweite positiv ist.
template<typename Iterator, typename Operation>
void iterate_ranges (Iterator from, Iterator to, Operation op) {
using R = typename std::iterator_traits<Iterator>::value_type;
using N = typename std::decay<decltype(std::declval<R>().first)>::type;
using P = std::pair<N, R>;
auto compare = [](P const & left, P const & right) {
return left.first > right.first;};
std::priority_queue<P, std::vector<P>, decltype(compare)> queue(compare);
auto push = [& queue] (P p) {
if (p.first < p.second.last) queue.push(p); };
auto next = [](P const & p) -> P {
assert(p.second.step > 0);
return {p.first + p.second.step, p.second}; };
auto init = [&push] (R const & r) {
push({r.first, r}); };
std::for_each(from, to, init);
if (queue.empty()) return;
N last = queue.top().first;
push(next(queue.top()));
queue.pop();
op(last);
while (! queue.empty()) {
P current = queue.top();
queue.pop();
if (current.first != last) {
op(current.first);
last = current.first;
}
push(next(current));
}
}
Speicherbedarf: in der Anzahl der Bereiche linear. Zeitbedarf: Summe aller Schrittzählungen in jedem Bereich.
Small example:
struct Range {
int first;
int last;
int step; // a better name ...
};
int main() {
Range ranges [] = {
{1, 10, 2},
{2, 50, 5}};
auto print = [](auto n) { std::cout << n << std::endl; };
iterate_ranges(std::begin(ranges), std::end(ranges), print);
}
Um alle Zahlen in einem Vektor zu erhalten, eine Lambda mit einem Verweis auf einen Vektor verwenden und drücken Sie jeden zurück.
Gibt es einen effizienteren Algorithmus, wenn Intervall immer 1 ist?
Sie könnten das als Sonderfall hinzufügen, aber ich denke nicht, dass es notwendig sein wird. Wenn Sie nur ~ 50 Bereiche haben, dann wird Push nicht so teuer sein. Obwohl, mit aller Optimierung: Profil zuerst!
Nicht [ 'std :: merge()'] (http://en.cppreference.com/w/cpp/algorithm/merge) arbeiten für Du? –
Schlägst du vor, fülle ich einen 'std :: vector' mit Zahlen aus 'Range' und dann' std :: merge' diese Vektoren? –
Kerndog73
das letzte Beispiel ist mir nicht klar, was meinst du mit 'std :: min (a.first, a.first)'? und für die ganze Frage, was willst du bekommen? und was "Intervall"? –