vendredi 3 avril 2015

Hash map with equivalence

I've decided to make a simple toy program: given a set of strings, count them with palindrome equivalence.


For instance, given { "abc", "123", "cba", "987" }, the map should be { {"abc", 2}, {"123", 1"}, {"987", 1"} }. I know that an unordered_map has the constraint that if hash values between two keys are the same, so it must be that operator== on the two mapped types should be true. As far as I remember, it doesn't state that those values must be the same (for instance at bits level), correct me if I'm wrong.


So I've decided to make a custom class of palindrome strings that contain a hash, and a custom hasher. The hash returns the minimum hash value between string and its reverse.


The problem: AFAIK, the mapped class should have a default constructor, and of course, if I add it, it would be meaningless.


Can you help me in this (at my first sight) easy task? Here's my code, not working of course!



// Forget all these includes, this is a "scratch" file
#include <iostream>
#include <iterator>
#include <type_traits>
#include <string>
#include <utility>
#include <vector>
#include <tuple>
#include <typeinfo>
#include <utility>
#include <iomanip>
#include <unordered_map>

// Palindrome strings
class palindrome
{
public:

// Returns the minimum hash value between fwd and rev strings
static std::size_t hash(std::string s)
{
auto fun = std::hash<std::string>();

auto fwd = fun(s);

std::reverse(s.begin(), s.end());

auto rev = fun(s);

return fwd < rev ? fwd : rev;
}

// Default constructor
palindrome()
{
// <----- DAMN! Strings and hashes are useless!
}

// Constructor
palindrome(std::string s) : s_{s}
{
hash_ = palindrome::hash(s);
}

// Compare hashes only
bool operator==(const palindrome &r) const
{
return hash_ == r.hash_;
}

// The string
std::string s_;

// Hash and count
std::size_t hash_, count_;
};

// Custom hashing function
class palindrome_hash
{
public:
std::size_t operator()(const palindrome &key) const
{
return palindrome::hash(key.s_);
}
};


int main(int argc, const char * argv[])
{
// The map
std::unordered_map<std::string, palindrome, palindrome_hash> map;

// The strings
std::vector<std::string> v { "abc", "124", "cba", "987" };

// Count all strings with palindrome equivalence
for(const auto &p : v)
{
std::cout << "inserting " << p << std::endl;

map[p].count_++; // <----- DAMN!
}

std::cout << std::endl;

// Dump 'em!
for(const auto &p : map)
{
std::cout << p.first << " -> " << p.second.s_ << " , " << std::hex << p.second.hash_ << std::endl;
}
}

Aucun commentaire:

Enregistrer un commentaire