initial commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
test
|
5
Makefile
Normal file
5
Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
test:
|
||||
$(CC) test.c ds.c ds.h -o test -g2 -Og && ./test
|
||||
|
||||
.PHONY: test
|
||||
.DEFAULT: test
|
49
README.md
Normal file
49
README.md
Normal file
@ -0,0 +1,49 @@
|
||||
# Data Structures
|
||||
Probably not the most efficient, but I don't really care (it's still faster
|
||||
than the average site using js).
|
||||
|
||||
## Singly/Doubly Linked List
|
||||
Example of working with a singly linked list (sll):
|
||||
```c
|
||||
char *a = "one";
|
||||
char *b = "two";
|
||||
ds_sll_t *ll = ds_sll_new_node(a); // [ "one" ]
|
||||
ds_sll_insert(ll, b); // [ "one", "two" ]
|
||||
ds_ll_foreach(ds_sll_t, ll) {
|
||||
puts(cur->data);
|
||||
// one
|
||||
// two
|
||||
}
|
||||
char *pa = ds_sll_remove(&ll, 0); // [ "two" ]
|
||||
char *pb = ds_sll_remove(&ll, 0); // [ ]
|
||||
```
|
||||
If you need a doubly linked list just use the equivalent `ds_dll` functions and
|
||||
datatypes.
|
||||
|
||||
## Hash Map
|
||||
```c
|
||||
struct complex {
|
||||
int num;
|
||||
char *str;
|
||||
};
|
||||
|
||||
struct complex *a = calloc(1, sizeof(struct complex));
|
||||
a->num = 1;
|
||||
a->str = "abc";
|
||||
struct complex *b = calloc(1, sizeof(struct complex));
|
||||
b->num = 2;
|
||||
b->str = "def";
|
||||
|
||||
ds_hmp_t *hmp = ds_hmp_init(101);
|
||||
ds_hmp_insert(hmp, a->str, a); // [ (23)[ [ a->str, a ] ] ]
|
||||
ds_hmp_insert(hmp, b->str, b); // [ (23)[ [ a->str, a ] ], (58)[ [ b->str, b ] ]
|
||||
struct complex *pa = ds_hmp_remove(hmp, a->str); // a
|
||||
free(pa->str);
|
||||
free(pa);
|
||||
ds_hmp_free(&hmp);
|
||||
free(b);
|
||||
```
|
||||
|
||||
# TODO
|
||||
- [ ] more data structures
|
||||
- [ ] tests
|
257
ds.c
Normal file
257
ds.c
Normal file
@ -0,0 +1,257 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ds.h"
|
||||
|
||||
ds_sll_t
|
||||
*ds_sll_new_node(void *data)
|
||||
{
|
||||
ds_sll_t *node;
|
||||
|
||||
node = calloc(1, sizeof(ds_sll_t));
|
||||
node->data = data;
|
||||
node->next = NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
ds_dll_t
|
||||
*ds_dll_new_node(void *data)
|
||||
{
|
||||
ds_dll_t *node;
|
||||
|
||||
node = calloc(1, sizeof(ds_dll_t));
|
||||
node->data = data;
|
||||
node->next = node->prev = NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void
|
||||
ds_sll_insert(ds_sll_t *ll, void *data)
|
||||
{
|
||||
ds_ll_foreach(ds_sll_t, ll) {
|
||||
if (!cur->data) {
|
||||
cur->data = data;
|
||||
return;
|
||||
} else if (!cur->next) {
|
||||
cur->next = ds_sll_new_node(data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ds_dll_insert(ds_dll_t *ll, void *data)
|
||||
{
|
||||
ds_ll_foreach(ds_dll_t, ll) {
|
||||
if (!cur->data) {
|
||||
cur->data = data;
|
||||
return;
|
||||
} else if (!cur->next) {
|
||||
cur->next = ds_dll_new_node(data);
|
||||
cur->next->prev = cur;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
*ds_sll_remove(ds_sll_t **ll, unsigned idx)
|
||||
{
|
||||
int i;
|
||||
void *data;
|
||||
ds_sll_t *cur, *rm;
|
||||
|
||||
if (!ll || !*ll) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = -1, cur = *ll;; i++, cur = cur->next) {
|
||||
if (i + 1 == idx) {
|
||||
if (idx == 0) {
|
||||
rm = cur;
|
||||
if (!rm) {
|
||||
return NULL;
|
||||
}
|
||||
*ll = cur->next;
|
||||
} else {
|
||||
rm = cur->next;
|
||||
if (!rm) {
|
||||
return NULL;
|
||||
}
|
||||
cur->next = cur->next->next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
data = rm->data;
|
||||
free(rm);
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
*ds_dll_remove(ds_dll_t **ll, unsigned idx)
|
||||
{
|
||||
int i;
|
||||
void *data;
|
||||
ds_dll_t *cur, *rm;
|
||||
|
||||
if (!ll || !*ll) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = -1, cur = *ll;; i++, cur = cur->next) {
|
||||
if (i + 1 == idx) {
|
||||
if (idx == 0) {
|
||||
rm = cur;
|
||||
if (!rm) {
|
||||
return NULL;
|
||||
}
|
||||
if (cur->next) {
|
||||
cur->next->prev = NULL;
|
||||
*ll = cur->next;
|
||||
}
|
||||
} else {
|
||||
rm = cur->next;
|
||||
if (!rm) {
|
||||
return NULL;
|
||||
}
|
||||
cur->next = cur->next->next;
|
||||
if (cur->next) {
|
||||
cur->next->prev = cur;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
data = rm->data;
|
||||
free(rm);
|
||||
return data;
|
||||
}
|
||||
|
||||
ds_hmp_t
|
||||
*ds_hmp_init(int data_len)
|
||||
{
|
||||
ds_hmp_t *hmp;
|
||||
|
||||
hmp = calloc(1, sizeof(ds_hmp_t));
|
||||
hmp->data_len = data_len;
|
||||
hmp->data = calloc(data_len, sizeof(ds_sll_t **));
|
||||
|
||||
return hmp;
|
||||
}
|
||||
|
||||
void
|
||||
ds_hmp_free(ds_hmp_t **hmp)
|
||||
{
|
||||
int i;
|
||||
_ds_hmp_kv_t *kv;
|
||||
ds_sll_t *ll;
|
||||
|
||||
if (!hmp || !*hmp) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < (*hmp)->data_len; i++) {
|
||||
ll = (*hmp)->data[i];
|
||||
while (ll && ll->data) {
|
||||
if ((kv = ds_sll_remove(&ll, 0))) {
|
||||
free(kv);
|
||||
}
|
||||
}
|
||||
if (ll) {
|
||||
free(ll);
|
||||
}
|
||||
}
|
||||
free((*hmp)->data);
|
||||
free(*hmp);
|
||||
}
|
||||
|
||||
int
|
||||
_ds_hmp_gen_hash(char *str)
|
||||
{
|
||||
unsigned long hash = 5381;
|
||||
int c;
|
||||
|
||||
while ((c = *str++)) {
|
||||
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
void
|
||||
ds_hmp_insert(ds_hmp_t *hmp, char *key, void *data)
|
||||
{
|
||||
_ds_hmp_kv_t *kv;
|
||||
ds_sll_t *ll;
|
||||
unsigned hash_pos;
|
||||
|
||||
kv = malloc(sizeof(_ds_hmp_kv_t));
|
||||
kv->key = key;
|
||||
kv->val = data;
|
||||
|
||||
hash_pos = _ds_hmp_gen_hash(key) % hmp->data_len;
|
||||
if (!hmp->data[hash_pos]) {
|
||||
hmp->data[hash_pos] = calloc(1, sizeof(ds_sll_t));
|
||||
}
|
||||
|
||||
/* get the ll and put the data into it */
|
||||
ll = hmp->data[hash_pos];
|
||||
ds_sll_insert(ll, kv);
|
||||
}
|
||||
|
||||
void
|
||||
*ds_hmp_get(ds_hmp_t *hmp, char *key)
|
||||
{
|
||||
ds_sll_t *cur, *ll;
|
||||
unsigned hash_pos;
|
||||
|
||||
hash_pos = _ds_hmp_gen_hash(key) % hmp->data_len;
|
||||
ll = hmp->data[hash_pos];
|
||||
if (!ll) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ds_ll_foreach(ds_sll_t, ll) {
|
||||
if (strcmp(((_ds_hmp_kv_t *)cur->data)->key, key) == 0) {
|
||||
return ((_ds_hmp_kv_t *)cur->data)->val;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
*ds_hmp_remove(ds_hmp_t *hmp, char *key)
|
||||
{
|
||||
int i;
|
||||
void *data;
|
||||
unsigned hash_pos;
|
||||
ds_sll_t *ll, *cur;
|
||||
_ds_hmp_kv_t *kv;
|
||||
|
||||
hash_pos = _ds_hmp_gen_hash(key) % hmp->data_len;
|
||||
ll = hmp->data[hash_pos];
|
||||
if (!ll) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0, cur = ll; cur; i++, cur = cur->next) {
|
||||
if (strcmp(((_ds_hmp_kv_t *)cur->data)->key, key) == 0) {
|
||||
kv = ds_sll_remove(&ll, i);
|
||||
hmp->data[hash_pos] = ll;
|
||||
if (!kv) {
|
||||
return NULL;
|
||||
}
|
||||
data = kv->val;
|
||||
free(kv);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
131
ds.h
Normal file
131
ds.h
Normal file
@ -0,0 +1,131 @@
|
||||
#ifndef _DS_LOADED
|
||||
#define _DS_LOADED
|
||||
|
||||
typedef struct _sll {
|
||||
struct _sll *next;
|
||||
void *data;
|
||||
} ds_sll_t;
|
||||
|
||||
typedef struct _dll {
|
||||
struct _dll *next;
|
||||
struct _dll *prev;
|
||||
void *data;
|
||||
} ds_dll_t;
|
||||
|
||||
typedef struct {
|
||||
ds_sll_t **data;
|
||||
unsigned data_len;
|
||||
} ds_hmp_t;
|
||||
|
||||
typedef struct {
|
||||
char *key;
|
||||
void *val;
|
||||
} _ds_hmp_kv_t;
|
||||
|
||||
#define ds_ll_foreach(t, ll) for (t *cur = ll; cur; cur = cur->next)
|
||||
|
||||
/**
|
||||
* @brief create a new allocated node for a singly linked list
|
||||
*
|
||||
* @param data the data you want to store
|
||||
* @return the node
|
||||
*/
|
||||
ds_sll_t *ds_sll_new_node(void *data);
|
||||
|
||||
/**
|
||||
* @brief create a new allocated node for a doubly linked list
|
||||
*
|
||||
* @param data the data you want to store
|
||||
* @return the node
|
||||
*/
|
||||
ds_dll_t *ds_dll_new_node(void *data);
|
||||
|
||||
/**
|
||||
* @brief data to insert into a singly linked list. This will use
|
||||
* ds_sll_new_node to create the node for you.
|
||||
*
|
||||
* @param ll singly linked list
|
||||
* @param data data you want to add
|
||||
*/
|
||||
void ds_sll_insert(ds_sll_t *ll, void *data);
|
||||
|
||||
/**
|
||||
* @brief data to insert into a doubly linked list. This will use
|
||||
* ds_sll_new_node to create the node for you.
|
||||
*
|
||||
* @param ll doubly linked list
|
||||
* @param data data you want to add
|
||||
*/
|
||||
void ds_dll_insert(ds_dll_t *ll, void *data);
|
||||
|
||||
/**
|
||||
* @brief remove an index from a singly linked list
|
||||
*
|
||||
* @param ll singly linked list
|
||||
* @param idx the node
|
||||
* @return the data in the node
|
||||
*/
|
||||
void *ds_sll_remove(ds_sll_t **ll, unsigned idx);
|
||||
|
||||
/**
|
||||
* @brief remove an index from a doubly linked list
|
||||
*
|
||||
* @param ll doubly linked list
|
||||
* @param idx the node
|
||||
* @return the data in the node
|
||||
*/
|
||||
void *ds_dll_remove(ds_dll_t **ll, unsigned idx);
|
||||
|
||||
/**
|
||||
* @brief initialize a new hashmap
|
||||
*
|
||||
* @param data_len the amount of slots in the array
|
||||
* @return the hashmap
|
||||
*/
|
||||
ds_hmp_t *ds_hmp_init(int data_len);
|
||||
|
||||
/**
|
||||
* @brief free all data allocated by ds_hmp_init and ds_hmp_insert
|
||||
*
|
||||
* @param hmp pointer to the hashmap
|
||||
*/
|
||||
void ds_hmp_free(ds_hmp_t **hmp);
|
||||
|
||||
/**
|
||||
* @brief generate a numerical hash from a given string. You shouldn't need to
|
||||
* use this, but it's available just incase.
|
||||
*
|
||||
* @param str
|
||||
* @return the hash
|
||||
*/
|
||||
int _ds_hmp_gen_hash(char *str);
|
||||
|
||||
/**
|
||||
* @brief insert data at key (which will be hashed using _ds_hmp_gen_hash). You
|
||||
* are responsible for freeing the key later.
|
||||
*
|
||||
* @param hmp the hashmap to insert into
|
||||
* @param key the key
|
||||
* @param data the data
|
||||
*/
|
||||
void ds_hmp_insert(ds_hmp_t *hmp, char *key, void *data);
|
||||
|
||||
/**
|
||||
* @brief get something from a hashmap using it's key
|
||||
*
|
||||
* @param hmp the hashmap
|
||||
* @param key the key where it's stored
|
||||
* @return the data stored at the key
|
||||
*/
|
||||
void *ds_hmp_get(ds_hmp_t *hmp, char *key);
|
||||
|
||||
/**
|
||||
* @brief remove something from a hashmap using it's key
|
||||
*
|
||||
* @param hmp the hashmap
|
||||
* @param key the key where it's stored
|
||||
* @return the data stored at the key
|
||||
*/
|
||||
void *ds_hmp_remove(ds_hmp_t *hmp, char *key);
|
||||
|
||||
#endif
|
41
test.c
Normal file
41
test.c
Normal file
@ -0,0 +1,41 @@
|
||||
#include "ds.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct complex {
|
||||
int num;
|
||||
char *str;
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char *a = "one";
|
||||
char *b = "two";
|
||||
ds_sll_t *ll = ds_sll_new_node(a); // [ "one" ]
|
||||
ds_sll_insert(ll, b); // [ "one", "two" ]
|
||||
ds_ll_foreach(ds_sll_t, ll) {
|
||||
puts(cur->data);
|
||||
}
|
||||
char *pa = ds_sll_remove(&ll, 0); // [ "two" ]
|
||||
char *pb = ds_sll_remove(&ll, 0); // [ ]
|
||||
|
||||
struct complex *a2 = calloc(1, sizeof(struct complex));
|
||||
a2->num = 1;
|
||||
a2->str = "abc";
|
||||
struct complex *b2 = calloc(1, sizeof(struct complex));
|
||||
b2->num = 2;
|
||||
b2->str = "def";
|
||||
|
||||
ds_hmp_t *hmp = ds_hmp_init(101);
|
||||
ds_hmp_insert(hmp, a2->str, a2); // [ (23)[ [ a->str, a ] ] ]
|
||||
ds_hmp_insert(hmp, b2->str, b2); // [ (23)[ [ a->str, a ] ], (58)[ [ b->str, b ] ]
|
||||
struct complex *pa2 = ds_hmp_remove(hmp, a2->str); // [ (23)[ [ a->str, a ] ]
|
||||
struct complex *pb2 = ds_hmp_remove(hmp, b2->str); // [ (58)[ [ b->str, b ] ]
|
||||
ds_hmp_free(&hmp);
|
||||
puts(pa2->str);
|
||||
puts(pb2->str);
|
||||
|
||||
free(pa2);
|
||||
free(pb2);
|
||||
}
|
Reference in New Issue
Block a user