From b27d2c1c640981ba215b189c926fab7137a9d98a Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Fri, 19 Feb 2021 11:07:59 +0900 Subject: [PATCH] Impl C solution to problem --- c_impl/.gitignore | 2 ++ c_impl/Makefile | 20 ++++++++++++ c_impl/src/main.c | 28 ++++++++++++++++ c_impl/src/map.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++ c_impl/src/map.h | 40 +++++++++++++++++++++++ problem | 1 + 6 files changed, 172 insertions(+) create mode 100644 c_impl/.gitignore create mode 100644 c_impl/Makefile create mode 100644 c_impl/src/main.c create mode 100644 c_impl/src/map.c create mode 100644 c_impl/src/map.h create mode 100644 problem diff --git a/c_impl/.gitignore b/c_impl/.gitignore new file mode 100644 index 0000000..f171474 --- /dev/null +++ b/c_impl/.gitignore @@ -0,0 +1,2 @@ +RunLengthEncoding +src/*.o diff --git a/c_impl/Makefile b/c_impl/Makefile new file mode 100644 index 0000000..f3fd8a4 --- /dev/null +++ b/c_impl/Makefile @@ -0,0 +1,20 @@ +SOURCES = src/main.c src/map.c +OBJECTS = $(subst .c,.o,$(SOURCES)) + +COMMON_FLAGS = -Wall -Wextra -Wpedantic +ifdef DEBUG + CFLAGS = $(COMMON_FLAGS) -O0 -g +else + CFLAGS = $(COMMON_FLAGS) -O3 -DNDEBUG +endif + +all: RunLengthEncoding + +RunLengthEncoding: $(OBJECTS) + $(CC) -o RunLengthEncoding $^ + +.PHONY: + +clean: + rm -f RunLengthEncoding + rm -f src/*.o diff --git a/c_impl/src/main.c b/c_impl/src/main.c new file mode 100644 index 0000000..a8b2e32 --- /dev/null +++ b/c_impl/src/main.c @@ -0,0 +1,28 @@ +#include +#include +#include + +#include "map.h" + +/* + * Requires keeping track of how many times each character is seen. It looks + * like it may require a map structure due to the fact that the given list is + * not necessarily in order. + */ + +int main(int argc, char **argv) { + if(argc != 2) { + return 1; + } + + CharMap map = initMap(); + + for(char *str = argv[1]; *str != 0; ++str) { + insertMap(map, *str); + } + + printMapContents(map); + + cleanupMap(map); + return 0; +} diff --git a/c_impl/src/map.c b/c_impl/src/map.c new file mode 100644 index 0000000..9a86659 --- /dev/null +++ b/c_impl/src/map.c @@ -0,0 +1,81 @@ +#include "map.h" + +#include +#include +#include + +CharMap initMap() { + CharMap map = (CharMap){0, MAP_INIT_SIZE, 0}; + + map.buckets = calloc(MAP_INIT_SIZE, sizeof(Bucket)); + for(unsigned int i = 0; i < MAP_INIT_SIZE; ++i) { + map.buckets[i].array = calloc(MAP_BUCKET_INIT_SIZE, sizeof(Item)); + map.buckets[i].capacity = 4; + } + + return map; +} + +void cleanupMap(CharMap map) { + for(unsigned int i = 0; i < map.capacity; ++i) { + free(map.buckets[i].array); + } + free(map.buckets); +} + +void insertMap(CharMap map, char item) { + // TODO recreate buckets when limit is reached + // though this is for practice, so it's not really necessary + unsigned int bucket_id = hasher(item) % map.capacity; + // first check if char exists in bucket + unsigned int i = 0; + for(; i < map.buckets[bucket_id].size; ++i) { + if(map.buckets[bucket_id].array[i].key == item) { + break; + } + } + + if(i < map.buckets[bucket_id].size) { + // exists in bucket, just increment the value + map.buckets[bucket_id].array[i].value += 1; + } else { + // does not exist, check if capacity is there for new entry + // and increase capacity if there isn't + if(map.buckets[bucket_id].capacity == map.buckets[bucket_id].size) { + Item *new_array = malloc(sizeof(Item) + * map.buckets[bucket_id].capacity * 2); + memcpy(new_array, map.buckets[bucket_id].array, map.buckets[bucket_id].capacity * sizeof(Item)); + free(map.buckets[bucket_id].array); + map.buckets[bucket_id].array = new_array; + map.buckets[bucket_id].capacity *= 2; + } + + map.buckets[bucket_id].array[map.buckets[bucket_id].size++] = (Item){item, 1}; + } +} + +unsigned int getMap(CharMap map, char item) { + unsigned int bucket_id = hasher(item) % map.capacity; + for(unsigned int i = 0; i < map.buckets[bucket_id].size; ++i) { + if(map.buckets[bucket_id].array[i].key == item) { + return map.buckets[bucket_id].array[i].value; + } + } + return 0; +} + +void printMapContents(CharMap map) { + for(unsigned int i = 0; i < map.capacity; ++i) { + for(unsigned int j = 0; j < map.buckets[i].capacity; ++j) { + if(map.buckets[i].array[j].value > 0) { + printf("%c has %d entries\n", map.buckets[i].array[j].key, + map.buckets[i].array[j].value); + } + } + } +} + +unsigned int hasher(char item) { + // really crappy hasher + return (((unsigned int)item) + 17) * 59; +} diff --git a/c_impl/src/map.h b/c_impl/src/map.h new file mode 100644 index 0000000..08d8180 --- /dev/null +++ b/c_impl/src/map.h @@ -0,0 +1,40 @@ +#ifndef PRACTICE_MAP_H +#define PRACTICE_MAP_H + +/* + * map contains a limited amount of buckets. Hashing the key will associate that + * key to a given bucket. When multiple keys are associated with the same + * bucket, use an array to hold multiple. Requries keys be hashable and + * equatable. + */ + +#define MAP_LIMIT 0.75 +#define MAP_INIT_SIZE 32 +#define MAP_BUCKET_INIT_SIZE 4 + +typedef struct Item { + char key; + unsigned int value; +} Item; + +typedef struct Bucket { + Item *array; + unsigned int capacity; + unsigned int size; +} Bucket; + +typedef struct CharMap { + Bucket *buckets; + unsigned int capacity; + unsigned int size; +} CharMap; + +CharMap initMap(); +void cleanupMap(CharMap map); +void insertMap(CharMap map, char item); +unsigned int getMap(CharMap map, char item); +void printMapContents(CharMap map); + +unsigned int hasher(char item); + +#endif diff --git a/problem b/problem new file mode 100644 index 0000000..3ee7baf --- /dev/null +++ b/problem @@ -0,0 +1 @@ +programmingpraxis.com February 9, 2021