2016-03-04 24 views
9

Perché in seguito la funzione di hash (che restituisce la costante 0) non sembra avere alcun effetto?unordered_map - La funzione hash non ha effetto

Poiché la funzione di hash restituisce una costante, mi aspettavo come uscita tutti i valori per essere 3. Tuttavia, sembra mappare in modo univoco i valori std::vector a un valore univoco, indipendentemente dalla costante della mia funzione di hash.

#include <iostream> 
#include <map> 
#include <unordered_map> 
#include <vector> 


// Hash returning always zero. 
class TVectorHash { 
public: 
    std::size_t operator()(const std::vector<int> &p) const { 
    return 0; 
    } 
}; 

int main() 
{ 
    std::unordered_map<std::vector<int> ,int, TVectorHash> table; 

    std::vector<int> value1({0,1}); 
    std::vector<int> value2({1,0}); 
    std::vector<int> value3({1,1}); 

    table[value1]=1; 
    table[value2]=2; 
    table[value3]=3; 

    std::cout << "\n1=" << table[value1]; 
    std::cout << "\n2=" << table[value2]; 
    std::cout << "\n3=" << table[value3]; 

    return 0; 
} 

Ottenuto uscita:

1=1 
2=2 
3=3 

uscita prevista:

1=3 
2=3 
3=3 

Che cosa mi manca circa hash?

+1

Sei eccetto che i tuoi dati spariscono quando l'hash diventa identico per dati diversi per sbaglio? – MikeCAT

+0

Non mi aspetto che svanisca. Ma mi aspetto che i dati vengano sovrascritti se la funzione hash mappa chiavi diverse nella stessa posizione. – rkioji

+1

Come usare la tabella '[your_hash_function (your_data)] = your_data;' dove 'table' è' std :: unordered_map'? – MikeCAT

risposta

14

È frainteso l'uso della funzione di hash: non è usato per confrontare gli elementi. Internamente, la mappa organizza gli elementi in bucket e la funzione di hash viene utilizzata per determinare il bucket in cui risiede l'elemento. Il confronto degli elementi viene eseguita con un altro parametro di template, cerca nella dichiarazione completa del modello unordered_map:

template< 
    class Key, 
    class T, 
    class Hash = std::hash<Key>, 
    class KeyEqual = std::equal_to<Key>, 
    class Allocator = std::allocator< std::pair<const Key, T> > 
> class unordered_map; 

Il parametro di modello successivo dopo la Hasher è il comparatore chiave. Per ottenere il comportamento che ci si aspetta, che avrebbe dovuto fare qualcosa di simile:

class TVectorEquals { 
public: 
    bool operator()(const std::vector<int>& lhs, const std::vector<int>& rhs) const { 
     return true; 
    } 
}; 

std::unordered_map<std::vector<int> ,int, TVectorHash, TVectorEquals> table; 

Ora la vostra mappa avrà un unico elemento e tutti i risultati saranno 3.

8

Un'implementazione di tabella hash sana non deve perdere informazioni, anche in presenza di collisioni di hash. Esistono diverse tecniche che consentono la risoluzione delle collisioni (in genere il trasferimento delle prestazioni di runtime all'integrità dei dati). Ovviamente, std::unordered_map lo implementa.

Vedi: Hash Collision Resolution

+0

Quindi, significa che avere una funzione di hash costante in realtà comprime la mia struttura di dati hash in un semplice elenco collegato (o qualsiasi altra struttura di dati utilizzata per risolvere le collisioni)? C'è un modo per disabilitare questo in C++? – rkioji

+3

@rkioji Same hash! = Stesso elemento.Ecco come * tutte * le mappe hash funzionano * per definizione. * Se vuoi una struttura dati che memorizza solo uno di ogni elemento con lo stesso hash, usa un comparatore di uguaglianza diverso per convincere la mappa che gli elementi con lo stesso hash sono identici. – Angew

+1

@rkioji Più simile a un semplice array dinamico. Tuttavia, la complessità del look-up è O (N) perché usa 'operator ==' o il comparatore di uguaglianza per cercare l'array in modo sequenziale. – juanchopanza

3

Aggiungere una classe di confronto chiave predicato.

class TComparer { 
public: 
    bool operator()(const std::vector<int> &a, const std::vector<int> &b) const { 
     return true; // this means that all keys are considered equal 
    } 
}; 

usare in questo modo:

std::unordered_map<std::vector<int> ,int, TVectorHash, TComparer> table; 

Poi il resto del codice funzionerà come previsto.

Problemi correlati