sucesiones secuencias secuencia para numéricas numeros numericas niños matematicas ejercicios ejemplos completar como c++ stl initialization stdset

c++ - para - secuencias numericas ejercicios



Inicializar de manera eficiente std:: set con una secuencia de números (4)

Bueno, puedes usar la versión de insert() de set<> en la que puedes proporcionar la posición como pista donde el elemento podría insertarse.

iterator insert ( iterator position, const value_type& x );

Complejidad: esta versión es logarítmica en general, pero se mantiene constante si se inserta x justo después del elemento apuntado por posición.

Un enfoque obvio (¿ingenuo?) Sería:

std::set<int> s; for (int i = 0; i < SIZE; ++i) { s.insert(i); }

Es razonablemente legible, pero por lo que entiendo, no es óptimo ya que implica buscar repetidamente la posición de inserción y no aprovecha el hecho de que la secuencia de entrada ya está ordenada.

¿Hay alguna manera más elegante / eficiente (o de hecho) de inicializar un std::set con una secuencia de números?

O, de forma más genérica, ¿cómo se puede insertar eficientemente una lista ordenada de entradas en una colección?

Actualizar:

Al revisar los documentos, acabo de notar que el constructor que acepta un iterador indica la posición para la inserción:

iterator insert ( iterator position, const value_type& x );

Lo que significa que esto sería más eficiente:

std::set<int> s; std::set<int>::iterator it = s.begin(); for (int i = 0; i < SIZE; ++i) { it = s.insert(it, i); }

Eso se ve razonablemente, pero todavía estoy abierto a más sugerencias.


El iterador derecho para usar como pista ha cambiado entre C ++ 03 y C ++ 11. Con C ++ 03, desea utilizar la posición del elemento anterior (tal como lo han mostrado usted y la mayoría de las respuestas).

En C ++ 11, quiere usar el iterador para el elemento inmediatamente después del que está por insertar. Cuando insertas en orden, esto hace las cosas un poco más simples: siempre usas your_container.end() :

std::set<int> s; for (int i = 0; i < SIZE; ++i) s.insert(s.end(), i);

Por supuesto, puede usar un algoritmo (p. Ej., std::iota ) o un iterador (por ej., boost::counting_iterator , como @pmr ya mencionado) para generar sus valores, pero en lo que respecta a la inserción en sí, para una corriente implementación que desea utilizar .end() como la sugerencia, en lugar del iterador devuelto por la inserción anterior.


Lo más lindo sería:

#include <set> #include <boost/iterator/counting_iterator.hpp> int main() { const int SIZE = 100; std::set<int> s(boost::counting_iterator<int>(0), boost::counting_iterator<int>(SIZE)); return 0; }

Si busca la eficiencia en bruto, puede ser útil usar la versión de inserción sugerida:

const int SIZE = 100; std::set<int> s; auto hint = s.begin(); for(int i = 0; i < SIZE; ++i) hint = s.insert(hint, i);

Ser capaz de declarar hint junto con el contador sería bueno y nos daría un alcance limpio, pero esto requiere struct piratería que me parece un poco ofuscante.

std::set<int> s; for(struct {int i; std::set<int>::iterator hint;} st = {0, s.begin()}; st.i < SIZE; ++(st.i)) st.hint = s.insert(st.hint, st.i);


#include <algorithm> #include <set> #include <iterator> int main() { std::set<int> s; int i = 0; std::generate_n(std::inserter(s, s.begin()), 10, [&i](){ return i++; }); }

Esto es (creo) equivalente a su segunda versión, pero en mi humilde opinión se ve mucho mejor.

La versión C ++ 03 sería:

struct inc { static int i; explicit inc(int i_) { i = i_; } int operator()() { return i++; } }; int inc::i = 0; int main() { std::set<int> s; std::generate_n(std::inserter(s, s.end()), SIZE, inc(0)); }