跳转至

hash_ref.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;
}