Actualmente tengo un std::map<std::string,int>
que almacena un valor entero en un identificador de cadena único, y busco la cadena. Hace principalmente lo que quiero, excepto que no realiza un seguimiento del pedido de inserción. Entonces, cuando itero el mapa para imprimir los valores, se ordenan de acuerdo con la cadena; pero quiero que se clasifiquen según el orden de (primera) inserción.
Pensé en usar a vector<pair<string,int>>
en su lugar, pero necesito buscar la cadena e incrementar los valores enteros alrededor de 10,000,000 de veces, así que no sé si a std::vector
será significativamente más lento.
¿Hay alguna forma de uso std::map
o hay otro std
contenedor que mejor se adapte a mis necesidades?
[Estoy en GCC 3.4 y probablemente no tengo más de 50 pares de valores en mi std::map
].
Gracias.
fuente
Respuestas:
Si solo tiene 50 valores en std :: map, puede copiarlos en std :: vector antes de imprimir y ordenarlos a través de std :: sort usando el functor apropiado.
O puede usar boost :: multi_index . Permite utilizar varios índices. En su caso, podría verse así:
fuente
Puede combinar a
std::vector
con astd::tr1::unordered_map
(una tabla hash). Aquí hay un enlace a la documentación de Boost paraunordered_map
. Puede utilizar el vector para realizar un seguimiento del orden de inserción y la tabla hash para realizar búsquedas frecuentes. Si está realizando cientos de miles de búsquedas, la diferencia entre la búsqueda O (log n)std::map
y O (1) para una tabla hash puede ser significativa.fuente
std::map
trabajar como se supone que debe (es decir, clasificándose a sí mismo a medida que inserta) y tiene un tiempo de ejecución rápido. (Leí esto después de escribir mi versión, ¡donde usé std :: list!)Mantenga un paralelo
list<string> insertionOrder
.Cuando llegue el momento de imprimir, repita la lista y busque en el mapa .
fuente
std::string_view
para las claves del mapa haciendo referencia astd::string
en lainsertionOrder
lista. Esto evita la copia, pero debe tener cuidado de que losinsertionOrder
elementos sobrevivan a las claves en el mapa que se refieren a ellos.Tessil tiene una muy buena implementación de mapa ordenado (y conjunto) que es una licencia MIT. Puede encontrarlo aquí: order-map
Ejemplo de mapa
fuente
Si necesita ambas estrategias de búsqueda, terminará con dos contenedores. Puede usar a
vector
con sus valores realesint
y poner unmap< string, vector< T >::difference_type>
junto a él, devolviendo el índice al vector.Para completar todo eso, puede encapsular ambos en una clase.
Pero creo que boost tiene un contenedor con múltiples índices.
fuente
Lo que quieres (sin recurrir a Boost) es lo que yo llamo un "hash ordenado", que es esencialmente un mashup de un hash y una lista vinculada con claves de cadena o enteras (o ambas al mismo tiempo). Un hash ordenado mantiene el orden de los elementos durante la iteración con el rendimiento absoluto de un hash.
He estado armando una biblioteca de fragmentos de C ++ relativamente nueva que llena lo que veo como agujeros en el lenguaje C ++ para los desarrolladores de bibliotecas de C ++. Ven aquí:
https://github.com/cubiclesoft/cross-platform-cpp
Agarrar:
Si los datos controlados por el usuario se colocarán en el hash, es posible que también desee:
Invocarlo:
Me encontré con este hilo de SO durante mi fase de investigación para ver si ya existía algo como OrderedHash sin que tuviera que colocar una biblioteca masiva. Estaba decepcionado. Así que escribí el mío. Y ahora lo he compartido.
fuente
No puede hacer eso con un mapa, pero puede usar dos estructuras separadas, el mapa y el vector y mantenerlos sincronizados, es decir, cuando elimina del mapa, encuentra y elimina el elemento del vector. O puede crear un
map<string, pair<int,int>>
- y en su par almacenar el tamaño () del mapa al insertarlo en la posición del registro, junto con el valor del int, y luego, cuando imprima, use el miembro de posición para ordenar.fuente
Otra forma de implementar esto es con a en
map
lugar de avector
. Le mostraré este enfoque y discutiré las diferencias:Simplemente cree una clase que tenga dos mapas detrás de escena.
A continuación, puede exponer un iterador a iterador
data_
en el orden correcto. La forma en que lo hace es iterarinsertion_order_
, y para cada elemento que obtenga de esa iteración, realice una búsqueda en eldata_
con el valor deinsertion_order_
Puede usar el más eficiente
hash_map
para insertion_order ya que no le importa iterar directamenteinsertion_order_
.Para hacer inserciones, puede tener un método como este:
Hay muchas formas en que puede mejorar el diseño y preocuparse por el rendimiento, pero este es un buen esqueleto para comenzar a implementar esta funcionalidad por su cuenta. Puede crear una plantilla y, de hecho, podría almacenar pares como valores en data_ para que pueda hacer referencia fácilmente a la entrada en insertion_order_. Pero dejo estos problemas de diseño como ejercicio :-).
Actualización : supongo que debería decir algo sobre la eficiencia de usar mapa frente a vector para insertion_order_
Quizás si no va a usar eliminaciones tanto, debería usar el enfoque vectorial. El enfoque del mapa sería mejor si estuviera admitiendo un orden diferente (como prioridad) en lugar de un orden de inserción.
fuente
Aquí hay una solución que requiere solo una biblioteca de plantillas estándar sin usar el índice múltiple de boost:
puede usar
std::map<std::string,int>;
yvector <data>;
dónde en el mapa almacena el índice de la ubicación de los datos en el vector y almacena los datos en el orden de inserción. Aquí el acceso a los datos tiene una complejidad O (log n). mostrar datos en orden de inserción tiene una complejidad O (n). la inserción de datos tiene una complejidad O (log n).Por ejemplo:
fuente
Esto está algo relacionado con la respuesta de Faisal. Puede crear una clase contenedora alrededor de un mapa y un vector y mantenerlos sincronizados fácilmente. La encapsulación adecuada le permitirá controlar el método de acceso y, por lo tanto, qué contenedor usar ... el vector o el mapa. Esto evita usar Boost o algo por el estilo.
fuente
Una cosa que debe tener en cuenta es la pequeña cantidad de elementos de datos que está utilizando. Es posible que sea más rápido usar solo el vector. Hay una sobrecarga en el mapa que puede hacer que sea más costoso realizar búsquedas en conjuntos de datos pequeños que con un vector más simple. Por lo tanto, si sabe que siempre utilizará aproximadamente la misma cantidad de elementos, haga una evaluación comparativa y vea si el rendimiento del mapa y el vector es lo que realmente cree que es. Puede encontrar que la búsqueda en un vector con solo 50 elementos es casi igual que el mapa.
fuente
// ¡Debería ser como este hombre!
// Esto mantiene que la complejidad de la inserción es O (logN) y la eliminación también es O (logN).
fuente
Úselo
boost::multi_index
con mapas y listas de índices.fuente
Un mapa de par (str, int) e int estático que se incrementa en las llamadas de inserción indexa pares de datos. ¿Poner una estructura que pueda devolver el valor int estático con un miembro index () quizás?
fuente