I wasn't sure how to calculate the number of permutations when certain characters are repeated.
I've since changed my approach, I am now looking at ways to sample the permutation space statistically for solutions that are more likely to occur, rather than trying all possibilities. If it grows so large that I run out of memory then a linear search would probably never finish either.
So, this topic can be considered solved as far as I'm concerned.
As for the hash map, it's usage is correct. it is my own container, and I use it because it's better than stdext::hash_map or std::map.
Feel free to criticize it though!
#pragma once
#include <vector>
#include <string>
#include <cstring>
#include "CoreMath.h"
typedef unsigned int UINT;
template<typename T>
struct is_equal
{
bool operator()(const T &a, const T &b) const
{
return (a == b);
}
};
template<typename T>
struct hash
{
UINT operator()(const T &key) const
{
long seed = static_cast<T>(key);
return static_cast<UINT>( rand(seed)*10000.0f );
}
};
template<>
UINT hash<std::string>::operator()(const std::string &str) const
{
UINT hash = 5381;
const char *c = str.c_str();
for(UINT i=0; i<str.size(); ++i)
hash = ((hash << 5) + hash) + *c++;
return hash;
}
template<typename Key = std::string, typename Val = UINT, UINT Alloc = 300, typename HashFcn = hash<Key>, typename EqualKey = is_equal<Key> >
class HashTable
{
struct HashEntry
{
Key myKey;
Val myVal;
HashEntry *next;
EqualKey myEqual;
HashEntry(const Key &_myKey, const Val &_myVal)
:next(NULL), myKey(_myKey), myVal(_myVal){}
void insert(const Key &_key, const Val &_val)
{
if ( myEqual(myKey, _key) )
myVal = _val;
else {
if (next == NULL) next = new HashEntry(_key, _val);
else next->insert(_key, _val);
}
}
void remove(const Key &_key)
{
if (next == NULL) return;
else next->remove(_key);
}
bool find(const Key &_key, Val &_val) const
{
if ( myEqual(myKey, _key) ){
_val = myVal;
return true;
} else {
if (next == NULL) return false;
else return next->find(_key, _val);
}
}
void deleteChain()
{
if (next != NULL){
next->deleteChain();
delete next;
}
}
};
HashEntry *data[Alloc];
HashFcn myHash;
EqualKey myEqual;
public:
HashTable()
{
memset(data, NULL, Alloc*sizeof(HashEntry*) );
}
~HashTable()
{
for(UINT i=0; i<Alloc; ++i)
{
if (data != NULL)
{
data->deleteChain();
delete data;
}
}
}
void insert(const Key &_key, const Val &_val)
{
UINT code = myHash(_key) % Alloc;
HashEntry *&entry = data;
if (entry == NULL) entry = new HashEntry(_key, _val);
else entry->insert(_key, _val);
}
void remove(const Key &_key)
{
UINT code = myHash(_key) % Alloc;
HashEntry *&entry = data;
if (entry == NULL) return;
else if ( myEqual(entry->myKey, _key) ) {
entry->deleteChain();
delete entry;
entry = NULL;
} else entry->remove(_key);
}
bool find(const Key &_key, Val &_val) const
{
UINT code = myHash(_key) % Alloc;
HashEntry *entry = data;
if (entry == NULL) return false;
else return entry->find(_key, _val);
}
struct Pair
{
Key key;
Val val;
};
class iterator : public std::iterator<std::forward_iterator_tag, Val >
{
UINT i;
HashEntry *const (*data);
HashEntry *entry;
EqualKey myEqual;
Pair myPair;
void advance()
{
if (i < 0 || i >= Alloc) return;
if (entry != NULL) entry = entry->next;
if (entry == NULL)
{
while(entry == NULL && ++i < Alloc)
entry = data;
}
}
public:
iterator(HashEntry *const _data[Alloc], UINT _i) : i(_i), data(_data), entry(NULL)
{
entry = data[0];
advance();
}
iterator& operator=(const iterator& other) {
i = other.i;
data = other.data;
entry = other.entry;
return(*this);
}
bool operator==(const iterator& other) const{
return (i == other.i && data == other.data && entry == other.entry);
}
bool operator!=(const iterator& other) const{
return !(operator==(other));
}
iterator& operator++() {
if (entry != NULL)
advance();
return (*this);
}
Pair *operator*()
{
if (entry != NULL){
myPair.key = entry->myKey;
myPair.val = entry->myVal;
return &myPair;
} else return NULL;
}
};
iterator begin() const
{
return iterator(data, 0);
}
iterator end() const
{
return iterator(data, Alloc);
}
};