learning-cc4e

Solution to https://cc4e.com/. If you copy these you're not right in the head.
Log | Files | Refs

commit 44d6b874ddf2dbaa34e7d8e09f9487b97224627a
parent b4a1b9263cb20d3a5f2c96d18c742c2d5efd40dd
Author: Yuval Langer <yuval.langer@gmail.com>
Date:   Thu,  2 Nov 2023 10:29:41 +0200

Add hash map.

Diffstat:
Ahash-map/main.c | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahash-map/output.txt | 16++++++++++++++++
Ahash-map/solution.c | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahash-map/student.c | 2++
4 files changed, 262 insertions(+), 0 deletions(-)

diff --git a/hash-map/main.c b/hash-map/main.c @@ -0,0 +1,146 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +struct HashMapEntry { + char *key; /* public */ + int value; /* public */ + struct HashMapEntry *__prev; + struct HashMapEntry *__next; +}; + +struct HashMapIter { + int __bucket; + struct HashMap *__map; + struct HashMapEntry *__current; + + struct HashMapEntry* (*next)(struct HashMapIter* self); + void (*del)(struct HashMapIter* self); +}; + +struct HashMap { + /* Attributes */ + int __buckets; + struct HashMapEntry *__heads[8]; + struct HashMapEntry *__tails[8]; + int __count; + + /* Methods */ + void (*put)(struct HashMap* self, char *key, int value); + int (*get)(struct HashMap* self, char *key, int def); + int (*size)(struct HashMap* self); + void (*dump)(struct HashMap* self); + struct HashMapIter* (*iter)(struct HashMap* self); + void (*del)(struct HashMap* self); +}; + +void __HashMap_del(struct HashMap* self) +{ + int i; + struct HashMapEntry *cur, *next; + + for(i=0; i<self->__buckets; i++) { + cur = self->__heads[i]; + while(cur) { + free(cur->key); + /* value is just part of the struct */ + next = cur->__next; + free(cur); + cur = next; + } + } + free((void *)self); +} + +void __HashMapIter_del(struct HashMapIter* self) { + free((void *)self); +} + +int getBucket(char *str, int buckets) +{ + int hash = 42; + if ( str == NULL ) return 0; + for( ; *str ; str++) { + hash = ( hash << 3 ) ^ *str; + } + return hash % buckets; +} + +void __HashMap_dump(struct HashMap* self) +{ + int i; + struct HashMapEntry *cur; + printf("Object HashHashMap count=%d buckets=%d\n", self->__count, self->__buckets); + for(i = 0; i < self->__buckets; i++ ) { + for(cur = self->__heads[i]; cur != NULL ; cur = cur->__next ) { + printf(" %s=%d [%d]\n", cur->key, cur->value, i); + } + } +} + +#include "student.c" + +struct HashMapIter* __HashMap_iter(struct HashMap* map) +{ + struct HashMapIter *iter = malloc(sizeof(*iter)); + iter->__map = map; + iter->__bucket = 0; + iter->__current = map->__heads[iter->__bucket]; + iter->next = &__HashMapIter_next; + iter->del = &__HashMapIter_del; + return iter; +} + +struct HashMap * HashMap_new() { + struct HashMap *p = malloc(sizeof(*p)); + int i; + + p->__buckets = 8; + for(i=0; i < p->__buckets; i++ ) { + p->__heads[i] = NULL; + p->__tails[i] = NULL; + } + + p->__count = 0; + + p->put = &__HashMap_put; + p->get = &__HashMap_get; + p->size = &__HashMap_size; + p->dump = &__HashMap_dump; + p->iter = &__HashMap_iter; + p->del = &__HashMap_del; + return p; +} + +int main(void) +{ + struct HashMap * map = HashMap_new(); + struct HashMapEntry *cur; + struct HashMapIter *iter; + + setvbuf(stdout, NULL, _IONBF, 0); /* Internal */ + + printf("Testing HashMap\n"); + map->put(map, "z", 8); + map->put(map, "z", 1); + map->put(map, "y", 2); + map->put(map, "b", 3); + map->put(map, "a", 4); + map->dump(map); + + printf("size=%d\n", map->size(map)); + + printf("z=%d\n", map->get(map, "z", 42)); + printf("x=%d\n", map->get(map, "x", 42)); + + printf("\nIterate\n"); + iter = map->iter(map); + while(1) { + cur = iter->next(iter); + if ( cur == NULL ) break; + printf(" %s=%d\n", cur->key, cur->value); + } + iter->del(iter); + + map->del(map); +} diff --git a/hash-map/output.txt b/hash-map/output.txt @@ -0,0 +1,15 @@ +Testing HashMap +Object HashHashMap count=4 buckets=8 + y=2 [1] + a=4 [1] + z=1 [2] + b=3 [2] +size=4 +z=1 +x=42 + +Iterate + y=2 + a=4 + z=1 + b=3 +\ No newline at end of file diff --git a/hash-map/solution.c b/hash-map/solution.c @@ -0,0 +1,98 @@ +struct HashMapEntry* __HashMap_find(struct HashMap* self, char *key, int bucket) +{ + /* TODO: Add some code here */ + struct HashMapEntry *current_entry; + + for (current_entry = self->__heads[bucket]; + current_entry != NULL; + current_entry = current_entry->__next) { + if (strcmp(current_entry->key, key) == 0) { + return current_entry; + } + } + + return NULL; +} + +void __HashMap_put(struct HashMap* self, char *key, int value) { + int bucket; + struct HashMapEntry *old, *new; + char *new_key; + if ( key == NULL ) return; + bucket = getBucket(key, self->__buckets); + old = __HashMap_find(self, key, bucket); + if ( old != NULL ) { + old->value = value; + return; + } + new = malloc(sizeof(*new)); + /* TODO: Add some code here */ + + new_key = malloc(sizeof(*new_key) * (strlen(key) + 1)); + new_key = strcpy(new_key, key); + new->key = new_key; + new->value = value; + new->__next = NULL; + + if (self->__heads[bucket] == NULL) { + new->__prev = NULL; + self->__heads[bucket] = new; + } + + if (self->__tails[bucket] != NULL) { + new->__prev = self->__tails[bucket]; + self->__tails[bucket]->__next = new; + } + + self->__tails[bucket] = new; + + self->__count++; +} + +int __HashMap_get(struct HashMap* self, char *key, int def) +{ + /* TODO: Add some code here */ + + struct HashMapEntry *result = __HashMap_find(self, + key, + getBucket(key, self->__buckets)); + + if (result != NULL) { + return result->value; + } + + return def; +} + +int __HashMap_size(struct HashMap* self) +{ + return self->__count; +} + +struct HashMapEntry* __HashMapIter_next(struct HashMapIter* self) +{ + /* TODO: Add some code here */ + + struct HashMapEntry *result; + + /* Out of the lecture. ~_~ */ + + while (self->__current == NULL) { + if (self->__bucket >= self->__map->__buckets) { + return NULL; + } + ++self->__bucket; + if (self->__bucket >= self->__map->__buckets) { + return NULL; + } + self->__current = self->__map->__heads[self->__bucket]; + } + + result = self->__current; + + if (self->__current != NULL) { + self->__current = self->__current->__next; + } + + return result; +} diff --git a/hash-map/student.c b/hash-map/student.c @@ -0,0 +1 @@ +/home/yuval/foo/cc4e/hash-map/solution.c +\ No newline at end of file