PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Ideen gesucht -> sgi: hash_map für vektoren mit double werten



Mat
13-10-2006, 16:53
Meine erste hash_map implementierung sieht so aus:



struct eqint
{
bool operator()(int d1, int d2) const
{
return d1 == d2;
}
};


struct MyHash
{
int operator()(const int key) const
{
int ret = 0;
//for each e in vector
ret = (ret * 31) + hash_i(key);
std::cout << "Der key: " << ret << std::endl;
return ret;
}

int hash_i(int x) const
{
return *(int*)&x;
}
};


Class::Class()
{
hash_map<int, double, MyHash, eqint> hash;

hash[0] = 3.0;
hash[0] = 2.7;
hash[1] = 2.5;
hash[2] = 15.3;

std::cout << " -> " << hash[2] << std::endl;
std::cout << " -> " << hash[0] << std::endl;
}


funktioniert auch.

Allerdings habe ich eine frage zu hash_map. Ich will meine eigene hash funktion verwenden. Diese ist doch dafür zuständig dass der schklüssel errechnet wird mit dem ich dann in konstanter zeit das hash element bekomme.
Nun habe ich einen vektor mit double werten als zu vergleichendes element.
also wenn der vektor bereits mal verwendet wurde sollten gewisse daten unter dessen schlüssel (der sich irgendwie aus den elementen des vektors errrechnnet) im hash vorhanden sein.
Meine Frage ist nun: Wie soll ich denn aus den double werten eine hash-funktion generieren? Schließlich werde ich nie identische schlüssel bekommen ...denn wie wir wissen ist folgendes:


double a = 8.4;
if(a == 8.4)
....


so net möglich.
Muss ich da auch irgendwie gegen ne untere schranke testen? Oder hat jemand einen Vorschlag wie man aus einem vektor mit double werten einen einheitlichen schlüssel generiert? Müsste irgendwie auf int oder long kommen um die eindeutigkeit zu halten...

Zusätzlich würde mich interessieren wie ich in meinem beispiel das zeug auf vektoren als eingabe übertragen kann. Im moment läuft es ja nur für integer und double werte als daten.
Ich brauche etwas was als zu vergleichendes element ein vektor eben sit mit double werten (woraus sich der schlüssel berechnen lässt) und als daten dann z.B 3 vektoren. Letzteres wäre evtl. über ein struct möglich?

Für Hilfe und Ideen bin ich sehr sehr dankbar.

Der Untergeher
14-10-2006, 17:14
Hallo,

direkt ne Lösung hab ich nicht für dich, aber vor nem ähnlichen Problem stand ich auch schonmal. Also:
In irgendwelchen Containeren die ihre Daten "verhashen" kann man naturgemäß effizient nur nach bitweise gleichen Daten suchen. Das ist ja gerade eine Eigenschaft guter Hashfunktionen - ganz ähnliches wird auf völlig verschiedenes abgebildet.
Wenn auch numerisch gleiche Vektoren gefunden werden sollen ist ein Ansatz, das man den ganzen Container durchgeht und auf sehr geringen Abstand testet - das erzeugt natürlich linearen Aufwand. Das geht auch schneller, erfordert dann aber Hirnschmalz. Stichwort zum einlesen ist "Range Query"; bei meinem Problem damals kam ich (glaub ich) auf einen Aufwand von O( k+ sqr(lg(n)) ) (k:anzahl der Treffer n: Punkte im Container). Die Lösung war allerdings sehr speziell auf die gespeicherten Datentypen zugeschnitten und in unverständlichem C gecodet.
Wenn du was STL-kompatibles findest schreib das mal in den thread hier - das würd mich auch interessieren.

Grüße
Daniel

PS: Ich hab grade mal unter "kd tree" gegoogelt (so ein Stichwort das ich noch im Hinterkopf hatte) ich glaub da kannst du was finden ...

PSS: Ich hab noch ein bisschen gegoogelt:
1. http://www.cacr.caltech.edu/~sean/projects/stlib/html/index.html
(unter Computational Geometry, ORQ Package; hervorragende Doku)
2. http://www.cgal.org/index.html

panzi
14-10-2006, 22:52
PSS: Ich hab noch ein bisschen gegoogelt: ...
<völlig nebensächliche besserwisserei>
Post Skriptum Skriptum?? Das sollte wohl Post Post Skriptum heißen. ;)
</völlig nebensächliche besserwisserei>

Mat
15-10-2006, 20:19
Danke :)
Diesen Fehler habe ich wohl mein ganzes leben bisher gemacht...bis heute :)

Aber nun zurück zu meinem Problem :)

Mat
15-10-2006, 22:20
hier ne methode wie es schon mal geht:

geht bestimmt noch viiiiil besser
aber mei :)



#include <iostream>

//hash_map is no C++ standard - so include the extensions due to gcc version
#if __GNUC__ < 3
#include <hash_map.h>
#else
#include <ext/hash_map>
using __gnu_cxx::hash_map;
#endif


typedef unsigned int uint32;
typedef unsigned long long uint64;


struct MyHash
{
uint32
operator()(const std::vector<double> vec) const
{
//Multipliing with 31 because the compiler will
//easily convert to 32 = 31 + 1
uint32 ret = 0;
for(uint i = 0; i < vec.size(); i++)
ret = (ret * 31) + hash_d(vec[i]);

std::cout << "Der key: " << ret << std::endl;
return ret;
}

//Take care: Reinterpret casting very dangerously!
//In my case under gcc 3.4.3 this is ok - test your
//compiler if problems will occur
inline uint32
hash_d(double x) const
{
uint64* p = reinterpret_cast< uint64* > (&x);
return *p ^ (*p >> 32);
}
};


struct HASH_DATA
{
std::vector<double> A_hat;
std::vector<double> m_k_hat;
int unit_vec_size;
int unit_vec_row;
};


Caching::Caching()
{
hash_map<std::vector<double>, HASH_DATA, MyHash> hash;


//NUR ZUM TESTEN....
struct HASH_DATA hd;
std::vector<double> a;
a.push_back(2.0);
a.push_back(2.9);
std::vector<double> b;
b.push_back(1.0);
b.push_back(1.9);
hd.A_hat = a;
hd.m_k_hat =b;
hd.unit_vec_row = 2;
hd.unit_vec_size = 1;

std::vector<double> t;
t.push_back(2.0);
t.push_back(5.009);
t.push_back(1.889);

std::vector<double> tmp;
tmp.push_back(2.0);
tmp.push_back(5.009);
tmp.push_back(1.889);
hash[t] = hd;
hash[tmp] = hd;
}