Skip to content

Commit

Permalink
basic hashset implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Caglankaan committed Mar 28, 2021
1 parent daee4e9 commit f7062fa
Show file tree
Hide file tree
Showing 4 changed files with 283 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.DS_Store
a.out*
build/
.vscode
97 changes: 97 additions & 0 deletions examples/hash_set_example.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#include "../hset/rtw_hset.h"

// This is hash_fun to get hash value of given key, in first example our key is
// char* so we are casting void * type to char *, at the end of function we are
// taking modular 30 because our bucket size is 30. So our key should be between
// 0-29.

unsigned long hash_func(const void *key) {
char *my_key = (char *)key;

unsigned long hash = 5381;
int c;

while ((c = *my_key++))
hash = ((hash << 5) + hash) + c;

return hash;
}

// This is a cmp_fun to identify if two strings are same or not.
// We will use this function when we try to push - get something from our set.
// If our key is char*(string) then we have to compare keys inorder to push to
// set or get from set.
int cmp_fun_str(const void *lhs, const void *rhs) {
return strcmp((char *)lhs, (char *)rhs) == 0;
}

void example_set_int() {
// in this example we will use our hashset like
// std::set<int> so our data is integer

// we have to create our hash set object with rtw_hset_init function.
// It takes 3 parameter, first one is predefined hash_func,
// Second one is our predefined comparasion function
// third one is sizeof our object (in this case its sizeof(int))
rtw_hset set = rtw_hset_init(&hash_func, &cmp_fun_str, sizeof(int));

int data1 = 5;
int data2 = 6;
int data3 = 12;

// To push pairs into our hash set our function is "rtw_hset_insert", it
// takes 2 parameter. First one is address of our set, second one is our data
rtw_hset_insert(&set, &data1);
rtw_hset_insert(&set, &data2);
rtw_hset_insert(&set, &data3);

// Now lets try to find our data. To do that our function is
// "rtw_hset_find", it takes 2 arg. First one is address of our set, second
// one is our data. If thereis value
// with given data it returns 1 otherwise it returns 0.

if (rtw_hset_find(&set, &data1))
printf("%d exists in hashet.\n", data1);
else
printf("data: %d couldn't found!\n", data1);

if (rtw_hset_find(&set, &data2))
printf("%d exists in hashset.\n", data2);
else
printf("data: %d couldn't found!\n", data2);

// This is a data which we do not have in our hset.
int data4 = 56;

if (rtw_hset_find(&set, &data4))
printf("%d exists in hashset.\n", data4);
else
printf("key: '%d' couldn't found!\n", data4);

// Now lets try to access our data3 and delete it from hset.
if (rtw_hset_find(&set, &data3))
printf("%d exists in hashset.\n", data3);
else
printf("data: %d couldn't found!\n", data3);

// Our data3 is in hset, so now lets try to delete it.
if (rtw_hset_del(&set, &data3))
printf("data: %d deleted from hset.\n", data3);
else
printf("data: %d does not exist on hset.\n", data3);

// We have deleted data3 already from set, lets try to delete it again.
if (rtw_hset_del(&set, &data3))
printf("data: %d deleted from hset.\n", data3);
else
printf("data: %d does not exist on hset.\n", data3);


rtw_hset_free(&set);
}
int main() {

printf("---- example of str as key ----\n");
example_set_int();

}
110 changes: 110 additions & 0 deletions hset/rtw_hset.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#include "rtw_hset.h"
#include <string.h>

rtw_hset rtw_hset_init(rtw_hset_hash_fn hash_fn, rtw_hset_eq_fn eq_fn,
size_t data_len) {
rtw_hset set;
set.hash_fn = hash_fn;
set.eq_fn = eq_fn;
set.data = rtw_vec_init(data_len);

memset(set.elements, 0, sizeof(set.elements));

return set;
}

int rtw_hset_del(rtw_hset *set, const void *data) {
unsigned long index = set->hash_fn(data) % RTW_HSET_BUCKET_SIZE_;

rtw_hset_elem_ *curr_node = set->elements[index];
rtw_hset_elem_ *prev_node = NULL;

while (NULL != curr_node) {
if (set->eq_fn(data, curr_node->data)) {
char last_elem[set->data.elem_len];
rtw_vec_pop_back(&set->data, last_elem);
if (1 != set->data.len) {
// Overwrite the deleted element's data with the last element's
// data. We don't delete the deleted key from the vector.
// Because it would be expensive. We overwrite the deleted
// element's data with the last element's data so that we only
// make 1 memcpy and no allocation.
memcpy(curr_node->data, last_elem, set->data.elem_len);
}

if (NULL == prev_node) {
set->elements[index] = curr_node->next;
} else {
prev_node->next = curr_node->next;
}

free(curr_node);
return 1;
}
prev_node = curr_node;
curr_node = curr_node->next;
}
return 0;
}

int rtw_hset_find(const rtw_hset *self, const void *data) {
unsigned long index = self->hash_fn(data) % RTW_HSET_BUCKET_SIZE_;
rtw_hset_elem_ *last = self->elements[index];
while (NULL != last) {
if (self->eq_fn(data, last->data)) {
return 1;
}
last = last->next;
}
return 0;
}

inline static rtw_hset_elem_ *
rtw_hset_elem_init_(rtw_hset *set, const void *data) {
// Key and value needed to be packed in a single memory location.
char temp[(set->data.elem_len)];
memcpy(temp, data, set->data_len);

rtw_vec_push_back(&set->data, temp);

rtw_hset_elem_ *item = (rtw_hset_elem_ *)malloc(sizeof(rtw_hset_elem_));
item->next = NULL;
item->data = rtw_vec_last(&set->data);

return item;
}

void rtw_hset_insert(rtw_hset *self, const void *data) {
unsigned long index = self->hash_fn(data) % RTW_HSET_BUCKET_SIZE_;

rtw_hset_elem_ *last = self->elements[index];
if (last == NULL) {
self->elements[index] = rtw_hset_elem_init_(self, data);
return;
}
for (;;) {
if (self->eq_fn(data, last->data)) {
return;
}
if (last->next == NULL)
break;
last = last->next;
}

last->next = rtw_hset_elem_init_(self, data);
}

void rtw_hset_free(rtw_hset *self) {
rtw_vec_free(&self->data);

for (int i = 0; i < RTW_HSET_BUCKET_SIZE_; i++) {
if (self->elements[i]) {
rtw_hset_elem_ *elem = self->elements[i];
while (elem != NULL) {
rtw_hset_elem_ *tmp = elem;
elem = elem->next;
free(tmp);
}
}
}
}
75 changes: 75 additions & 0 deletions hset/rtw_hset.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include "../vec/rtw_vec.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define RTW_HSET_BUCKET_SIZE_ 30

typedef unsigned long (*rtw_hset_hash_fn)(const void *);
typedef int (*rtw_hset_eq_fn)(const void *, const void *);

typedef struct rtw_hset_elem_s_ {
void *data;
struct rtw_hset_elem_s_ *next;
} rtw_hset_elem_;

typedef struct {
rtw_hset_hash_fn hash_fn;
rtw_hset_eq_fn eq_fn;
rtw_hset_elem_ *elements[RTW_HSET_BUCKET_SIZE_];
rtw_vec data;
size_t data_len;
} rtw_hset;

/**
* Creates an empty binary set without any allocation
*
* @param cmp_fn Is function pointer to add our datas to hash set, comparasion
* function. Help of this comp_fn we will know if incoming data exists in set or
* not. It takes 2 parameters, left hand side and right hand side. It returns -1
* if right hand side is greater than left hand side It returns 1 if right hand
* side is smaller than left hand side It returns 0 if two value is same.
* @param hash_fn Is function pointer to hash data, hash function.
* It takes only one void* parameter and get hash of that value.
* It returns a hash value with int.
* @param data_len Size of the data that the vector holds
*/
rtw_hset rtw_hset_init(rtw_hset_hash_fn hash_fn, rtw_hset_eq_fn eq_fn,
size_t data_len);

/**
* Deletes an element from hash set with given data.
*
* @param self Pointer to this set
* @param data Pointer to the data
* @return if deletion operation is success it returns 1, otherwise it returns 0.
*/
int rtw_hset_del(rtw_hset *self, const void *data);

/**
* Finds the element with given data from 'self' .
*
* @param self Pointer to this set
* @param data Pointer to the data
*
* @return 1 if element found, 0 otherwise.
*/
int rtw_hset_find(const rtw_hset *self, const void *data);

/**
* Adds the data pointed by 'data' to the set.
*
* @param self Pointer to this set.
* @param data Pointer to data that will be inserted.
*
*/
void rtw_hset_insert(rtw_hset *self, const void *data);

/**
* Frees allocated memory for this set.
*
* @param self Pointer to this set.
*
*/
void rtw_hset_free(rtw_hset *self);

0 comments on commit f7062fa

Please sign in to comment.