186 lines
5.0 KiB
C
186 lines
5.0 KiB
C
#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;
|
||
|
|
}
|