Impl C solution to problem
This commit is contained in:
parent
bb33d969c0
commit
b27d2c1c64
6 changed files with 172 additions and 0 deletions
2
c_impl/.gitignore
vendored
Normal file
2
c_impl/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
RunLengthEncoding
|
||||
src/*.o
|
20
c_impl/Makefile
Normal file
20
c_impl/Makefile
Normal file
|
@ -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
|
28
c_impl/src/main.c
Normal file
28
c_impl/src/main.c
Normal file
|
@ -0,0 +1,28 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
81
c_impl/src/map.c
Normal file
81
c_impl/src/map.c
Normal file
|
@ -0,0 +1,81 @@
|
|||
#include "map.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
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;
|
||||
}
|
40
c_impl/src/map.h
Normal file
40
c_impl/src/map.h
Normal file
|
@ -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
|
1
problem
Normal file
1
problem
Normal file
|
@ -0,0 +1 @@
|
|||
programmingpraxis.com February 9, 2021
|
Loading…
Reference in a new issue