#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "time.h"
#define DEFAULT_MAP_SIZE 1<<5
#define MAX_MAP_SIZE 1<<30
#define CAPACITY_FACTOR 0.6f
#define MAX_KEY_LENGTH 1<<3
typedef unsigned int Hash;
typedef char* Key;
typedef int Value;
typedef struct Entry{
struct Entry *next;
Hash hash;
Value value;
Key key;
}Entry;
typedef struct HashMap{
Entry** heads;
Value nul;
unsigned int size;
unsigned int usage;
unsigned int realCapacity; //size * CAPACITY_FACTOR
unsigned int sizeForIndex; //size - 1
}HashMap;
HashMap* create(unsigned int);
HashMap* transfer(HashMap*, HashMap*);
Hash hash(char[]);
HashMap* put(HashMap*, Key, Value);
HashMap* putInHeads(HashMap*, int, Hash, Key, Value);
HashMap* putInList(HashMap*, int, Hash, Key, Value);
HashMap* resize(HashMap*);
int find(char[]);
void print(HashMap*);
HashMap* create(unsigned int size){
HashMap* hashMap = malloc(sizeof(HashMap));
int i;
hashMap->size = size;
hashMap->sizeForIndex = size - 1;
hashMap->realCapacity = (unsigned int)(size * CAPACITY_FACTOR);
hashMap->usage = 0;
hashMap->heads = calloc(size, sizeof(Entry*));
hashMap->nul = 0;
return hashMap;
}
HashMap* transfer(HashMap* newHashMap, HashMap* oldHashMap){
unsigned int oldIndex, newIndex;
Entry *oldEntry, *oldNextEntry;
for (oldIndex = 0; oldIndex < oldHashMap->size; oldIndex++){
if (oldHashMap->heads[oldIndex] != NULL){
oldEntry = oldHashMap->heads[oldIndex];
do{
newIndex = (oldEntry->hash) & (newHashMap->sizeForIndex);
oldNextEntry = oldEntry->next;
oldEntry->next = newHashMap->heads[newIndex];
newHashMap->heads[newIndex] = oldEntry;
oldEntry = oldNextEntry;
} while (oldEntry != NULL);
}
}
newHashMap->usage = oldHashMap->usage;
newHashMap->nul = oldHashMap->nul;
free(oldHashMap->heads);
oldHashMap->heads = NULL;
free(oldHashMap);
oldHashMap = NULL;
return newHashMap;
}
Hash hashCode(char* key){
int offset = 5;
Hash hashCode = 0;
while (*key) hashCode = (hashCode << offset) + (*key++);
return hashCode;
}
HashMap* put(HashMap* hashMap, Key key, Value value){
if (key == NULL){
hashMap->nul = value;
return hashMap;
}
Hash hash = hashCode(key);
int index = hash & (hashMap->sizeForIndex);
if (hashMap->heads[index] == NULL){
return putInHeads(hashMap, index, hash, key, value);
} else {
return putInList(hashMap, index, hash, key, value);
}
}
HashMap* putInHeads(HashMap* hashMap, int index, Hash hash, Key key, Value value){
Entry* newHead = malloc(sizeof(Entry));
newHead->hash = hash;
newHead->key = _strdup(key);
newHead->value = value;
newHead->next = NULL;
hashMap->heads[index] = newHead;
(hashMap->usage)++;
if (hashMap->usage > hashMap->realCapacity) return resize(hashMap);
return hashMap;
}
HashMap* putInList(HashMap* hashMap, int index, Hash hash, Key key, Value value){
Entry* lastEntry = hashMap->heads[index];
while (lastEntry != NULL){
if (lastEntry->hash == hash){
lastEntry->value += value;
return hashMap;
}
else lastEntry = lastEntry->next;
}
lastEntry = malloc(sizeof(Entry));
lastEntry->hash = hash;
lastEntry->key = _strdup(key);
lastEntry->value = value;
lastEntry->next = hashMap->heads[index];
hashMap->heads[index] = lastEntry;
(hashMap->usage)++;
if (hashMap->usage > hashMap->realCapacity) return resize(hashMap);
return hashMap;
}
HashMap* resize(HashMap* hashMap){
HashMap* newHashMap;
if ((hashMap->size << 1) <= MAX_MAP_SIZE) {
newHashMap = create((hashMap->size << 1));
newHashMap = transfer(newHashMap, hashMap);
return newHashMap;
}
return hashMap;
}
Value get(HashMap* hashMap, Key key){
Hash hash = hashCode(key);
int index = hash & (hashMap->sizeForIndex);
Entry* entry = hashMap->heads[index];
while (entry != NULL){
if (entry->hash == hash) return entry->value;
entry = entry->next;
}
return NULL;
}
void print(HashMap* hashMap){
unsigned int i;
Entry* entry;
for (i = 0; i < hashMap->size; i++){
entry = hashMap->heads[i];
while (entry != NULL){
printf("%s: %d\n", entry->key, entry->value);
entry = entry->next;
}
}
}
int main(){
clock_t start, end;
HashMap* hashMap = create(DEFAULT_MAP_SIZE);
FILE* fp;
char filePath[0xFF];
char line[5];
char key[MAX_KEY_LENGTH];
printf("input file path: ");
scanf_s("%s", filePath, 0xFF);
if (fopen_s(&fp, filePath, "r") == 0){
start = clock();
while (fgets(line, 5, fp) != NULL){
line[3] = '\0';
hashMap = put(hashMap, line, 1);
}
end = clock();
printf("\n%fs", (float)(end - start)/1000);
fclose(fp);
print(hashMap);
} else {
printf("can't open file");
}
return 0;
}