Cod sursa(job #923165)

Utilizator maritimCristian Lambru maritim Data 23 martie 2013 12:36:12
Problema Hashuri Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 9.17 kb
#include<iostream>
#include<vector>
#include<stdlib.h>
#include<time.h>
#include<fstream>
#include<ctype.h>
#include<string>
using namespace std;
 
template <class DataType,class Conversion>
class CuckooHash
{
    private:
        int hashA1,hashA2,hashB1,hashB2;
        int M1,M2,size,limit;
        int prime;
        DataType uninserted,*null;
        DataType *Hash1,*Hash2;
        DataType *aux;
 
        void makeSizes(void);
        int hashFunction1(DataType x);
        int hashFunction2(DataType x);
        void remakeFunctions(void);
        int reinsert(DataType x);
        int rehash(void);
        int insertTry(DataType x);
 
    public:
        CuckooHash(void);
        CuckooHash(int M1,int M2);
        ~CuckooHash(void);
        DataType operator+=(const DataType&);
        int operator-=(const DataType&);
        int operator<(const DataType&);
        int clean(void);
        template<class DataType2,class Conversion2> friend istream& operator>>(istream&,CuckooHash<DataType2,Conversion2> &);
        template<class DataType2,class Conversion2> friend ostream& operator<<(ostream&,CuckooHash<DataType2,Conversion2> &);
};

template<class DataType,class Conversion>
CuckooHash<DataType,Conversion>::CuckooHash(void)
{
    srand(time(NULL));
 
    this->M1 = 1000003;
    this->M2 = 1000033;
 
    prime = 1000000009;
 
    Hash1 = new DataType[M1];
    Hash2 = new DataType[M2];
    aux = new DataType[M1+M2];

    null = new DataType;
    this->clean();
 
    remakeFunctions();
}
 
template<class DataType,class Conversion>
CuckooHash<DataType,Conversion>::CuckooHash(int M1,int M2)
{
    srand(time(NULL));

    this->M1 = M1;
    this->M2 = M2;
 
    prime = 1000000009;
 
    Hash1 = new DataType[M1];
    Hash2 = new DataType[M2];
    aux = new DataType[M1+M2];

    null = new DataType;
    this->clean();
 
    remakeFunctions();
}

template<class DataType,class Conversion>
int CuckooHash<DataType,Conversion>::hashFunction1(DataType x)
{
    Conversion conversion;

    int y = conversion(x);
    y = abs(y);
    return ((1LL*hashA1*y+hashA2)%prime)%M1;
}
 
template<class DataType,class Conversion>
int CuckooHash<DataType,Conversion>::hashFunction2(DataType x)
{
    Conversion conversion;

    int y = conversion(x);
    y = abs(y);
    return ((1LL*hashB2*y+hashB1)%prime)%M2;
}
 
template<class DataType,class Conversion>
void CuckooHash<DataType,Conversion>::remakeFunctions(void)
{
    hashA1 = rand()%prime;
    hashA2 = rand()%prime;
    hashB1 = rand()%prime;
    hashB2 = rand()%prime;
}

template<class DataType,class Conversion>
void CuckooHash<DataType,Conversion>::makeSizes(void)
{
    this->M1 = 1000011 + rand()%666013;
    this->M2 = 1000011 + rand()%666013;
 
    this->M1 += 1-(this->M1 & 1);
    this->M2 += 1-(this->M2 & 1);
 
}
 
template<class DataType,class Conversion>
inline int CuckooHash<DataType,Conversion>::rehash(void)
{
    /*Functia de rehash. Se iau toate elementele
    din hash si se pastreaza separat. Se goleste
    hashul si se incearca reinserarea fiecarui 
    element folosind functii de hash diferite.*/

    int limit = -1;

    aux[++limit] = uninserted;
 
    for(int i=0;i<M1;i++)
        if(Hash1[i] != *null)
            aux[++limit] = Hash1[i];
 
    for(int i=0;i<M2;i++)
        if(Hash2[i] != *null)
            aux[++limit] = Hash2[i];
 
    int i = limit;
 
    for(;;)
    {
       for(int j=0;j<=limit;j++)
            *this -= aux[j];
 
        remakeFunctions();
 
        for(i=0;i<=limit;i++)
            if(!insertTry(aux[i]))
                break;
 
        if(i == limit+1)
        {
            return 1;
        }
    }

    return 0;
}
 
template<class DataType,class Conversion>
inline int CuckooHash<DataType,Conversion>::reinsert(DataType x)
{
    /*Functia care incearca sa reinsereze
    elementul x. Inserarea se face alternativ
    intre cei doi vectori. Daca pozitia pe care
    incearca sa insereze elementul x este o cupata
    se elimina elementul respectiv, se atribuie 
    pozitiei valoarea lui x si se apeleaza
    recursiv functia reinsert pentru valoarea
    eliminata.*/

    int hash_funct2 = hashFunction2(x),
        hash_funct1 = hashFunction1(x);
 
    if(size == 0)
    {
        uninserted = x;
        return 0;
    }
 
    if(size & 1)
    {
        if(Hash1[hash_funct1] != *null)
        {
            DataType y = Hash1[hash_funct1];
            Hash1[hash_funct1] = x;
            -- size;
            return reinsert(y);
        }
        else if(size & 1)
        {
            Hash1[hash_funct1] = x;
            return 1;
        }
    }
    else
    {
        if(Hash2[hash_funct2] != *null)
        {
            DataType y = Hash2[hash_funct2];
            Hash2[hash_funct2] = x;
            -- size;
            return reinsert(y);
        }
        else
        {
            Hash2[hash_funct2] = x;
            return 1;
        }
    }

    return 0;
}
 
template<class DataType,class Conversion>
inline int CuckooHash<DataType,Conversion>::insertTry(DataType x)
{
    /*Functia care verifica daca un element
    poate fi inserat in Hash. Daca poate sa il
    insereze, il insereaza, iar daca nu, pastreaza
    ultimul element neinserat in variabila privata
    "inserted"*/

    int hash_funct1 = hashFunction1(x);
 
    if(*this<x)
    {
        return 1;
    }
 
    if(Hash1[hash_funct1] != *null)
    {
        DataType y = Hash1[hash_funct1];
        Hash1[hash_funct1] = x;
        size = 20;
        return reinsert(y);
    }
    else
    {
        Hash1[hash_funct1] = x;
        return 1;
    }
}
 
template<class DataType,class Conversion>
inline DataType CuckooHash<DataType,Conversion>::operator+=(const DataType& nou)
{
    /*Functia publica de insert care
    incearca sa insereze valoarea x
    si daca nu reuseste apeleaza functia
    rehash.*/

    if(!insertTry(nou))
    {
        rehash();
    }
 
    return nou;
}
 
template<class DataType,class Conversion>
inline int CuckooHash<DataType,Conversion>::operator-=(const DataType& nou)
{
    /*Daca exista valoarea x in hash
    se elimina, atribuindu-se pozitiei 
    valoarea 0*/

    int hash_funct1 = hashFunction1(nou);
    int hash_funct2 = hashFunction2(nou);
 
    if(Hash1[hash_funct1] == nou)
    {
        Hash1[hash_funct1] = *null;
        return 1;
    }
    else if(Hash2[hash_funct2] == nou)
    {
        Hash2[hash_funct2] = *null;
        return 1;
    }
 
    return -1;
}
 
template<class DataType,class Conversion>
inline int CuckooHash<DataType,Conversion>::operator<(const DataType& nou)
{
    /*Se cauta valoarea x in hash.
    Daca valoarea nu se gaseste in niciunul
    dintre cei 2 vectori inseamna ca nu exista
    in hash!*/

    int hash_funct1 = hashFunction1(nou);
    int hash_funct2 = hashFunction2(nou);
 
    if(Hash1[hash_funct1] == nou)
    {
        return 1;
    }
    else if(Hash2[hash_funct2] == nou)
    {
        return 1;
    }
 
    return 0;
}

template<class DataType,class Conversion>
CuckooHash<DataType,Conversion>::~CuckooHash(void)
{
    /*Elibereaza memoria folosita de
    tabelele de dispersie si de vectorul
    auxiliar*/

    delete[] Hash1;
    delete[] Hash2;
    delete[] aux;
}

template<class DataType,class Conversion>
int CuckooHash<DataType,Conversion>::clean(void)
{
    try
    {
        for(int i=0;i<M1;i++)
            Hash1[i] = *null;
        for(int i=0;i<M2;i++)
            Hash2[i] = *null;
        return 1;
    }
    catch(int e)
    {
        return 0;
    }
}

template<class DataType2,class Conversion2>
istream& operator>>(istream& in,CuckooHash<DataType2,Conversion2>& Hash)
{
    /*Citeste hash-ul primit ca parametru 
    din fisierul de intrare primit ca stream*/
    char op;
    DataType2 aux;

    for(;(in>>op);)
    {
        if(op == '+' || op == '-')
        {
            in >> aux;
            if(op == '+')
                Hash += aux;
            else
                Hash -= aux;
        }
    }

    return in;
}

template<class DataType2,class Conversion2>
ostream& operator<<(ostream& out,CuckooHash<DataType2,Conversion2>& Hash)
{
    for(int i=0;i<Hash.M1;i++)
        if(Hash.Hash1[i] != *(Hash.null))
            out << Hash.Hash1[i] << " ";
    for(int i=0;i<Hash.M2;i++)
        if(Hash.Hash2[i] != *(Hash.null))
            out << Hash.Hash2[i] << " ";

    return out;
}

struct conversion {
    int operator() (const int& x)
        { return x; }
} ;

struct conversion2 {
    int operator() (const double& x)
        { return (int)(x*10000); }
} ;

struct conversion3 {
    int operator() (const string& x)
        { 
            int a = 1;
            for(int i=0;i<x.size();i++)
                a = a*26+x[i];
            
            return a;
        }
};

int main()
{
    ifstream f("hashuri.in");
    ofstream g("hashuri.out");
 
    int N,op,a;
 
    CuckooHash<int,conversion> Hash;
 
    f >> N;
 
    for(int i=1;i<=N;i++)
    {
        f >> op >> a;
         
        switch(op)
        {
            case 1 : Hash += a;
                break;
            case 2 : Hash -= a;
                break;
            case 3 : g << (Hash<a) << "\n";
        }
    }
 
    f.close();
    g.close();

/*    ifstream f("fisier.txt");
    ofstream g("fisier2.txt");

    CuckooHash<int,conversion> Hash;
    CuckooHash<double,conversion2> Hash2;
    CuckooHash<string,conversion3> Hash3;

    f >> Hash3;
    cout << Hash3;
    
    f.close();*/
}