Cod sursa(job #708922)

Utilizator vlad.doruIon Vlad-Doru vlad.doru Data 7 martie 2012 15:49:41
Problema Hashuri Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 4.3 kb
// Ion Vlad-Doru, Grupa 135, Facultatea de Matematica si Informatica
// Cuckoo Hashing, Programare Orientata pe Obiecte

#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdlib>

#define NA -1
#define FREE 0

using namespace std;

ifstream in("hashuri.in");
ofstream out("hashuri.out");

const int PRIM=1073807359; // numarul prim mare folosit la evaluarea functiilor de hash random

class hash_function{ // h(x)=((a*x+b)%p)%m unde a si b sunt random si a!=0
	int a,b,p,m;
public:
	void generate(int prim,int h_size); // genereaza valorile a si b primind p si m
	int evaluate(int x); // evalueaza functia in punctul x
};

void hash_function::generate(int prim,int h_size){
	this->p=prim;
	this->m=h_size;
	this->a=(rand())%(this->m);
	while(this->a==0) // ne asiguram ca a e diferit de 0
		this->a=(rand())%(this->m);
	this->b=(rand())%(this->m);
	return;
}

int hash_function::evaluate(int x){
	long long value; // intram pe long long
	value=(long long)((long long)a*(long long)x+(long long)b);
	value%=p;
	value%=m;
	return (int)value;
}

class hash{
	int size; // dimensiunea hashului
	int *h; // vom aloca dinamic un vector h de dimensiune size
	int p; // p numar random folosit pentru functiile de hash
	hash_function h1,h2;
public:
	hash(int hash_size);
	~hash();
	int find(int value);
	void erase(int value);
	bool insert(int value); // returneaza 1 daca insereaza cu succes si 0 fara succes ceea ce implica refacerea hashului
};

hash::hash(int hash_size){
	this->size=hash_size*4; // aloc de doua ori numarul maxim de elemente ce se vor gasi in hash in acelasi timp deoarece fiecare element are doua valori de hashing asociate
	this->h=new int[this->size];
	for(int i=0;i<=size;++i) // initializam tabelul cu FREE peste tot
		h[i]=FREE;
	this->p=PRIM;
	this->h1.generate(this->p,this->size); // generez functiile random
	this->h2.generate(this->p,this->size);
}

hash::~hash(){
	delete[] this->h; // sterg zona alocata dinamica in hash
}

int hash::find(int value){ // caut valoarea value in una din cele doua pozitii posibile;
	int location1=this->h1.evaluate(value),location2=this->h2.evaluate(value);
	if(h[location1]==value)
		return location1;
	if(h[location2]==value)
		return location2;
	return NA;
}

void hash::erase(int value){ // eliberez locatia ocupata de value daca exista
	int location=find(value);
	if(location!=NA)
		h[location]=FREE;
}		

bool hash::insert(int value){ // inserez valuarea value in tabel
	int aux,ant=value,location1,location2,explorated=0,upper_bound=(int)log((double)size);
	location1=h1.evaluate(value); // location1=h1(value)
	if(find(value)!=NA) // daca e deja inserat atunci iesim din metoda
		return true;
	if(h[location1]==FREE){ // daca prima locatie e libera il inseram in hash
		h[location1]=value;
		return true;
	}
	else{ //altfel scoatem ce se afla in hash pe prima locatie si punem elementul curent pe prima sa locatie
		aux=h[location1];
		h[location1]=value;
		explorated++;
	}
	while(explorated<=upper_bound){ // cat timp am scos mai putin de log(hash size) elemente executam
		location1=h1.evaluate(aux);//calculam cele 2 pozitii posibile si ne uitam la ce diferita de pozitia de pe care elementul a fost scos
		location2=h2.evaluate(aux);
		if(h[location2]==ant){ // elementul a fost scos de pe pozita data de h2 si il inseram pe pozitia data de h1
			if(h[location1]==FREE){ // daca aceasta a doua pozitie e libera inseram elementul
				h[location1]=aux;
				return true;
			}
			else{ // altfel scoatem elementul de pe pozitia h1 si inseram elementul nostru
				ant=aux;
				aux=h[location1];
				h[location1]=ant;
			}
		}
		else{ // elementul a fost scos de pe pozitia data de h1
			if(h[location2]==FREE){ //cazul se rezolva analog cu primul
				h[location2]=aux;
				return true;
			}
			else{
				ant=aux;
				aux=h[location2];
				h[location2]=ant;
			}
		}
		explorated++; // crestem numarul de elemente explorate
	}
	return false;
}
	

int main(){
	int operations,value,opcode,ok=1;
	in>>operations;
	hash H(operations);	// declaram hashul necesar pentru un numar dat de operatii
	for(int i=1;i<=operations;++i){
		in>>opcode>>value;
		if(opcode==1){
			ok=H.insert(value);
			if(!ok){
				cout<<"E nevoie de rehashing";
				break;
			}
			continue;
		}				
		if(opcode==2)
			H.erase(value);
		if(opcode==3){
			if(H.find(value)==NA)
				out<<"0\n";
			else
				out<<"1\n";
		}
	}
	return 0;
}