-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
635 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,254 @@ | ||
#include "hashFO.h" | ||
|
||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
|
||
/** | ||
* Creates a .hash file with empty buckets. | ||
* Returns 0 if success, -1 if error. | ||
*/ | ||
int createEmptyHashFile(char *hashFile){ | ||
FILE *hFile; | ||
Bucket b; | ||
int i, nBuckets; | ||
|
||
if(NULL == (hFile = fopen(hashFile, "wb"))) | ||
return -1; | ||
|
||
|
||
memset(&b, 0, sizeof(Bucket)); | ||
nBuckets = BUCKETS + OVERFLOW_BUCKETS; | ||
|
||
for(i=0; i<nBuckets; i++){ | ||
fwrite(&b, sizeof(Bucket), 1, hFile); | ||
} | ||
|
||
fclose(hFile); | ||
return 0; | ||
} | ||
|
||
|
||
/** | ||
* Creates a .hash file from a .dat file. It reads people info from | ||
* a .dat file and inserts it to buckets in .hash file. | ||
* It returns: | ||
* - (-1) if params error | ||
* - (-2) if cannot open .dat file | ||
* - number of overflowing registers that where inserted. | ||
*/ | ||
int createHashFromBinaryFile(char *binaryFile, char *hashFile){ | ||
if(-1 == createEmptyHashFile(hashFile)) | ||
return -1; | ||
|
||
FILE *inFile, *outFile; | ||
if(NULL == (inFile = fopen(binaryFile, "rb"))) return -2; | ||
|
||
Person p; | ||
Bucket b; | ||
int nOverflows = 0; | ||
int insertedBucket; | ||
|
||
while(fread(&p, sizeof(Person), 1, inFile)){ | ||
insertedBucket = insertRegister(&p, hashFile); | ||
|
||
if(insertedBucket >= BUCKETS) | ||
nOverflows++; | ||
} | ||
return nOverflows; | ||
} | ||
|
||
|
||
/** | ||
* Reads, interprets and prints a .hash file to see how data is stored. | ||
* Returns the total number of buckets the .hash file stores (including | ||
* buckets in overflowing area), or -1 if cannot open the .hash file. | ||
*/ | ||
int readHashFile(char *hashFile){ | ||
FILE *hFile; | ||
Bucket b; | ||
int i,j,n; | ||
|
||
if(NULL == (hFile = fopen(hashFile, "rb"))) | ||
return -1; | ||
|
||
rewind(hFile); | ||
|
||
i = 0; | ||
fread(&b, sizeof(Bucket), 1, hFile); | ||
while(!feof(hFile)){ | ||
for(j=0; j<CAPACITY; j++){ | ||
if(j == 0){ | ||
printf("\x1b[36;1m==============================================================\n"); | ||
printf("\x1b[33;3;4mBucket %2d (%02d registers assigned)\n\x1b[0m",i, b.size); | ||
} | ||
|
||
if(j < b.size) | ||
printf("\t\t\t%-8s %-19s %-19s %-19s %-11s\n", b.registers[j].dni, b.registers[j].name, | ||
b.registers[j].surname1,b.registers[j].surname2,b.registers[j].province); | ||
else | ||
printf("\n"); | ||
} | ||
|
||
i++; | ||
fread(&b, sizeof(Bucket), 1, hFile); | ||
} | ||
|
||
printf("\x1b[36;1m==============================================================\n\x1b[0m"); | ||
fclose(hFile); | ||
return i; | ||
} | ||
|
||
|
||
/** | ||
* Searches for a register in a .hash file given a dni. | ||
* It returns: | ||
* - (-1) if params error | ||
* - (-2) if cannot open .hash file | ||
* - (-3) if dni is not stored in .hash file | ||
* - bucket number where dni has been found | ||
*/ | ||
int searchRegister(char *dni, char *hashFile, Person *p){ | ||
if(dni == NULL || hashFile == NULL || p == NULL) | ||
return -1; | ||
|
||
FILE *hFile; | ||
if(NULL == (hFile = fopen(hashFile, "rb"))) | ||
return -2; | ||
|
||
int i; | ||
Bucket b; | ||
|
||
//Move to the bucket where dni should be stored according to the hashFile | ||
fseek(hFile, HASH_BUCKET(atoi(dni)), SEEK_SET); | ||
fread(&b, sizeof(Bucket), 1, hFile); | ||
|
||
//Look if the dni is in that bucket. If it is not in the cube: | ||
// - If bucket size < CAPACITY -> dni is not stored anywhere | ||
// - If bucket size >= CAPACITY -> dni might be stored in overflow zone | ||
for(i=0; i<CAPACITY && i<b.size; i++){ | ||
if(strcmp(b.registers[i].dni, dni) == 0){ | ||
*p = b.registers[i]; | ||
return HASH(atoi(dni)); | ||
} | ||
} | ||
|
||
if(b.size < CAPACITY) | ||
return -3; | ||
else{ | ||
int bucketReaded; | ||
|
||
//Move to overflow zone | ||
fseek(hFile, OVERFLOW_ZONE, SEEK_SET); | ||
|
||
bucketReaded = 0; | ||
while(fread(&b, sizeof(Bucket), 1, hFile)){ | ||
for(i=0; i<CAPACITY && i<b.size; i++){ | ||
if(strcmp(b.registers[i].dni, dni) == 0){ | ||
*p = b.registers[i]; | ||
return BUCKETS + bucketReaded; | ||
} | ||
} | ||
|
||
//If the last bucket is reached (last is not full) and | ||
// dni was not found, dni is not stored anywhere. | ||
if(b.size < CAPACITY) | ||
return -3; | ||
|
||
bucketReaded++; | ||
} | ||
} | ||
} | ||
|
||
|
||
/** | ||
* Inserts a new register (person) in a .hash file. | ||
* - (-1) if params error | ||
* - (-2) if cannot open .hash file | ||
* - (-3) if there is no more available space to store people | ||
* - bucket number where dni has been stored if success | ||
*/ | ||
int insertRegister(Person *p, char *hashFile){ | ||
if(p == NULL || hashFile == NULL) | ||
return -1; | ||
|
||
FILE *hFile; | ||
if(NULL == (hFile = fopen(hashFile, "rb+"))){ | ||
return -2; | ||
} | ||
|
||
Bucket b; | ||
|
||
//Move pointer to the cube where the register in going to be | ||
// stored, according to the DNI hash | ||
fseek(hFile, HASH_BUCKET(atoi(p->dni)), SEEK_SET); | ||
|
||
//Reads the cube from the file: | ||
// - If bucket size < CAPACITY -> Bucket has space to store the registers | ||
// - If bucket size >= CAPACITY -> Bucket has no space, register is stores in overflow zone. | ||
fread(&b, sizeof(Bucket), 1, hFile); | ||
|
||
if(b.size < CAPACITY){ | ||
b.registers[b.size] = *p; | ||
(b.size)++; | ||
|
||
//Move pointer back to the bucket again and overwrite it | ||
fseek(hFile, -sizeof(Bucket), SEEK_CUR); | ||
fwrite(&b, sizeof(Bucket), 1, hFile); | ||
|
||
fclose(hFile); | ||
return HASH(atoi(p->dni)); | ||
|
||
}else{ | ||
int i, bucketToRead; | ||
|
||
//Increment size and rewrite the register that is full. | ||
b.size++; | ||
fseek(hFile, -sizeof(Bucket), SEEK_CUR); | ||
fwrite(&b, sizeof(Bucket), 1, hFile); | ||
|
||
//Move to overflow zone and search for a empty space to | ||
// store the register. If there is no more space available, | ||
// it returns -3. | ||
fseek(hFile, OVERFLOW_ZONE, SEEK_SET); | ||
|
||
bucketToRead = 0; | ||
fread(&b, sizeof(Bucket), 1, hFile); | ||
|
||
while(!(b.size < CAPACITY)){ | ||
bucketToRead++; | ||
if(bucketToRead == OVERFLOW_BUCKETS){ | ||
fclose(hFile); | ||
return -3; | ||
} | ||
|
||
fread(&b, sizeof(Bucket), 1, hFile); | ||
} | ||
|
||
|
||
//If there is a bucket with available space, inserts the register | ||
// and overwrites the bucket in the file. | ||
b.registers[b.size] = *p; | ||
fseek(hFile, -sizeof(Bucket), SEEK_CUR); | ||
fwrite(&b, sizeof(Bucket), 1, hFile); | ||
|
||
//Finally, increments the number of registers assigned in all | ||
// overflow buckets located before the bucket where the register | ||
// was saved | ||
fseek(hFile, OVERFLOW_ZONE, SEEK_SET); | ||
for(i=0; i<=bucketToRead; i++){ | ||
//Read cube | ||
fread(&b, sizeof(Bucket), 1, hFile); | ||
//Increment size | ||
b.size++; | ||
//Overwrite cube | ||
fseek(hFile, -sizeof(Bucket), SEEK_CUR); | ||
fwrite(&b, sizeof(Bucket), 1, hFile); | ||
} | ||
|
||
fclose(hFile); | ||
return (BUCKETS + bucketToRead); | ||
} | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
#ifndef __HASH_FO_H__ | ||
#define __HASH_FO_H__ | ||
|
||
#define CAPACITY 5 | ||
#define BUCKETS 20 | ||
#define OVERFLOW_BUCKETS 4 | ||
|
||
//Auxiliar "functions" | ||
#define HASH(K) ((K)%BUCKETS) | ||
#define HASH_BUCKET(K) ((HASH(K))*sizeof(Bucket)) | ||
#define OVERFLOW_ZONE (BUCKETS*sizeof(Bucket)) | ||
|
||
|
||
/** | ||
* Each struct is stored in a bucket according to a hash. This hash is | ||
* calculated with the dni of the person using modulus formula: | ||
* hash = dni % BUCKETS | ||
* | ||
* Each calculated hash is related to a specific bucket where that person | ||
* is/is going to be stored. | ||
* | ||
* If all (20) buckets all full, there is a auxiliar zone to store more people. | ||
* This is called "Overflow zone", and has a capacity of 4 more buckets. This zone | ||
* is a secuential area that stores people when the bucket that corresponds to the hash | ||
* calculated with a dni is full. When a person is stored in this zone, the size of the | ||
* cube where the person should have been stored is increased even if it is stored in | ||
* the overflow zone. This lets the user know that there should be more people than there | ||
* are in the full bucket, and that they are stored in the overflow zone. | ||
* | ||
* If both the (20)buckets and overflow zone are full, no more people can be inserted. | ||
*/ | ||
|
||
typedef struct person{ | ||
char dni[9]; | ||
char name[19]; | ||
char surname1[19]; | ||
char surname2[19]; | ||
char province[11]; | ||
}Person; | ||
|
||
|
||
typedef struct bucket{ | ||
Person registers[CAPACITY]; | ||
int size; | ||
}Bucket; | ||
|
||
|
||
//Create hash file | ||
int createEmptyHashFile(char *hashFile); | ||
int createHashFromBinaryFile(char *binaryFile, char *hashFile); | ||
|
||
//Functions | ||
int readHashFile(char *hashFile); | ||
int searchRegister(char *dni, char *hashFile, Person *p); | ||
int insertRegister(Person *p, char *hashFile); | ||
|
||
|
||
//TODO: deleteRegister function (reduce bucket size and relocate overflow zone registers | ||
// that should have been in the buckets) | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
#include "hashFO.h" | ||
|
||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
|
||
int main(void){ | ||
int i, nOverflows; | ||
FILE *f; | ||
Person p; | ||
char hashFile[12] = "people.hash"; | ||
char dni[9]; | ||
|
||
nOverflows = createHashFromBinaryFile("people.dat", hashFile); | ||
i = readHashFile(hashFile); | ||
|
||
printf("\n\n\x1b[33;3;4mTotal Cubes:\x1b[0;35;1m %d\x1b[0m \n", i); | ||
printf("\x1b[33;3;4mOverflowing registers:\x1b[0;35;1m %d\x1b[0m \n\n", nOverflows); | ||
|
||
//Search registers | ||
strcpy(dni,"7389298"); //Exists in a bucket | ||
i = searchRegister(dni, hashFile, &p); | ||
switch(i){ | ||
case -1: printf("\x1b[31;1mError in searchRegister\x1b[0m \n"); break; | ||
case -2: printf("\x1b[31;1mError cannot open file in searchRegister!!!\x1b[0m \n"); break; | ||
case -3: printf("\x1b[31;1mCannot find person with dni %s\x1b[0m \n", dni); break; | ||
default: printf("\x1b[32;1mRegister finded in BUCKET %d:",i); | ||
printf("\x1b[0;36;1m %s %s %s %s %s \x1b[0m \n", p.dni, p.name, p.surname1, | ||
p.surname2,p.province); | ||
} | ||
|
||
|
||
strcpy(dni,"7219752"); //Exists in a overflow zone | ||
i = searchRegister(dni, hashFile, &p); | ||
switch(i){ | ||
case -1: printf("\x1b[31;1mError in searchRegister\x1b[0m \n"); break; | ||
case -2: printf("\x1b[31;1mError cannot open file in searchRegister!!!\x1b[0m \n"); break; | ||
case -3: printf("\x1b[31;1mCannot find person with dni %s\x1b[0m \n", dni); break; | ||
default: printf("\x1b[32;1mRegister finded in BUCKET %d:",i); | ||
printf("\x1b[0;36;1m %s %s %s %s %s \x1b[0m \n", p.dni, p.name, p.surname1, | ||
p.surname2,p.province); | ||
} | ||
|
||
|
||
strcpy(dni,"12345678"); //Dont exist | ||
i = searchRegister(dni, hashFile, &p); | ||
switch(i){ | ||
case -1: printf("\x1b[31;1mError in searchRegister\x1b[0m \n"); break; | ||
case -2: printf("\x1b[31;1mError cannot open file in searchRegister!!!\x1b[0m \n"); break; | ||
case -3: printf("\x1b[31;1mCannot find person with dni %s\x1b[0m \n", dni); break; | ||
default: printf("\x1b[32;1mRegister finded in BUCKET %d:",i); | ||
printf("\x1b[0;36;1m %s %s %s %s %s \x1b[0m \n", p.dni, p.name, p.surname1, | ||
p.surname2,p.province); | ||
} | ||
|
||
|
||
//Insert register | ||
printf("\n"); | ||
Person newPerson = {"12345678","Hi","im","new","Salamanca"}; //Inserts in overflow zone | ||
i = insertRegister(&newPerson, hashFile); | ||
switch(i){ | ||
case -1: printf("\x1b[31;1mError in insertRegister\x1b[0m \n"); break; | ||
case -2: printf("\x1b[31;1mError cannot open file in insertRegister!!!\x1b[0m \n"); break; | ||
case -3: printf("\x1b[31;1mNo more space available to insert\x1b[0m \n"); break; | ||
default: printf("\x1b[32;1mRegister inserted in BUCKET %d \n",i); | ||
} | ||
|
||
|
||
Person otherNewPerson = {"19493800","Other","new","person","Salamanca"}; //Inserts in bucket 0 | ||
i = insertRegister(&otherNewPerson, hashFile); | ||
switch(i){ | ||
case -1: printf("\x1b[31;1mError in insertRegister\x1b[0m \n"); break; | ||
case -2: printf("\x1b[31;1mError cannot open file in insertRegister!!!\x1b[0m \n"); break; | ||
case -3: printf("\x1b[31;1mNo more space available to insert\x1b[0m \n"); break; | ||
default: printf("\x1b[32;1mRegister inserted in BUCKET %d \n",i); | ||
} | ||
|
||
//readHashFile(hashFile); | ||
|
||
printf("\n"); | ||
return 0; | ||
} |
Oops, something went wrong.