Directorio de artículos
- prefacio
- 1. Prueba de uso y rendimiento de unordered_map
- En segundo lugar, el uso de unordered_set
- 1. Ejercicios
- Resumir
prefacio
Comparemos la diferencia entre unordered_map y map:
Al ver esto, todos han descubierto que, de hecho, sus funciones son exactamente las mismas, pero la capa inferior es diferente. Nota: el mapa y el conjunto usan iteradores bidireccionales, las series desordenadas usan iteradores unidireccionales
mapa / conjunto: la capa inferior es un árbol rojo-negro
unordered_map / unordered_set: la capa inferior es una tabla hash
¿Por qué diseñarlos a ambos? ¡Porque la eficiencia de búsqueda de hash es muy alta!
Vamos a la parte de uso:
1. El uso de unordered_map
#include <unordered_map>
#include <unordered_set>
#include <iostream>
using namespace std;
void unordered_map_test()
{
unordered_map<string, int> ump;
ump.insert(make_pair("left", 1));
ump.insert(make_pair("right", 2));
ump.insert(make_pair("string", 3));
ump.insert(make_pair("list", 4));
ump.insert(make_pair("list", 5));
for (auto& e : ump)
{
cout << e.first << ":" << e.second << endl;
}
cout << endl;
unordered_map<string, int>::iterator it = ump.begin();
while (it != ump.end())
{
cout << it->first << ":" << it->second << endl;
++it;
}
}
int main()
{
unordered_map_test();
}
Podemos ver que el uso de unordered es exactamente el mismo que el de map. Los datos repetidos no se insertarán. Por supuesto, también hay series unordered_multimap que admiten la inserción de datos repetidos. Entonces, ¿cuál es la principal diferencia? Vamos a ver:
Se puede ver que la principal diferencia es que la serie desordenada está desordenada, a continuación damos las pruebas de desempeño del mapa y la serie desordenada:
void unordered_map_test2()
{
const size_t N = 1000000;
unordered_set<int> us;
set<int> s;
vector<int> v;
v.reserve(N);
srand(time(0));
for (size_t i = 0; i < N; ++i)
{
v.push_back(rand());
//v.push_back(rand()+i);
//v.push_back(i);
}
size_t begin1 = clock();
for (auto e : v)
{
s.insert(e);
}
size_t end1 = clock();
cout << "set insert:" << end1 - begin1 << endl;
size_t begin2 = clock();
for (auto e : v)
{
us.insert(e);
}
size_t end2 = clock();
cout << "unordered_set insert:" << end2 - begin2 << endl;
size_t begin3 = clock();
for (auto e : v)
{
s.find(e);
}
size_t end3 = clock();
cout << "set find:" << end3 - begin3 << endl;
size_t begin4 = clock();
for (auto e : v)
{
us.find(e);
}
size_t end4 = clock();
cout << "unordered_set find:" << end4 - begin4 << endl << endl;
cout << s.size() << endl;
cout << us.size() << endl << endl;;
size_t begin5 = clock();
for (auto e : v)
{
s.erase(e);
}
size_t end5 = clock();
cout << "set erase:" << end5 - begin5 << endl;
size_t begin6 = clock();
for (auto e : v)
{
us.erase(e);
}
size_t end6 = clock();
cout << "unordered_set erase:" << end6 - begin6 << endl << endl;
}
Comencemos con 10000 números aleatorios como ejemplo:
Podemos ver que todas las funciones de la serie hash son más rápidas que las ordinarias. Comparemos 100.000 números aleatorios:
Se puede ver que la serie desordenada es aún más rápida, y otros 1.000.000:
A partir de los resultados anteriores, podemos ver por qué c ++ agrega una nueva serie hash.Los siguientes son los datos medidos por otra máquina:
Resumen: en términos de varios escenarios, el rendimiento general de la serie desordenada es mejor, especialmente encontrar es el mejor.
En segundo lugar, el uso de unordered_set
Del mismo modo, veamos si hay alguna diferencia funcional entre set y hash set:
Como dijimos antes, set es un iterador bidireccional y hash series es un iterador unidireccional. Excepto por la diferencia del iterador, otras funciones son casi iguales. Demostremos cómo usar las funciones básicas:
void unordered_set_test()
{
unordered_set<int> ust;
ust.insert(1);
ust.insert(7);
ust.insert(4);
ust.insert(9);
ust.insert(3);
for (auto& e : ust)
{
cout << e << " ";
}
cout << endl;
unordered_set<int>::iterator it = ust.begin();
while (it != ust.end())
{
cout << *it << " ";
++it;
}
}
int main()
{
unordered_set_test();
}
Ejercicios:
La misma diferencia con el conjunto no está ordenado. Lo anterior es el uso de todas las series hash de contenido. A continuación, usamos la serie hash para practicar una pregunta:
Intersección I de dos números:
Ritko Enlace: Rikko
La intersección solo necesita encontrar los mismos elementos de las dos matrices, y el título nos dice que cada elemento es único, por lo que no hay elementos duplicados.
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> us1(nums1.begin(),nums1.end());
unordered_set<int> us2(nums2.begin(),nums2.end());
vector<int> v;
for (auto& e:us1)
{
if (us2.find(e)!=us2.end())
{
v.push_back(e);
}
}
return v;
}
};
Primero colocamos los números de las dos matrices en el conjunto hash respectivamente, luego recorremos el primer conjunto hash (también puede atravesar el segundo) y luego dejamos que el segundo conjunto hash encuentre el primer valor If en un conjunto hash se encuentra, significa que el número es una intersección y lo coloca en la matriz, y finalmente devuelve la matriz.
Resumir
El contenedor de la serie hash es casi el mismo que el contenedor anterior. Es más fácil usar el contenedor STL con frecuencia. En el próximo artículo, explicaremos el principio subyacente de la tabla hash y lo implementaremos. Por lo tanto, si desea Realice la capa subyacente, aún necesita saber cuál es el contenedor. Cómo usarlo, puede realizar la función.