tries data structure implementation......... Application - Dictionary - c

Wanted to write a program to implement a dictionary of words using Tries Data Structure.
Please tell me the structure for the implementation so that I could start the program, as i haven't got any article on internet, for Tries Implementation..
The confusion is, that when we search through the word, and we get through the word at the leaf node, only then is the meaning of the word would be stored.. But all the nodes in Tries data structure will be of waste. i.e. storing a variable of meaning in every internal node......
So, the basic idea, is with a help of small example as how to store dictionary, please let me know the structure for Tries Data Structure..
And please C program Implementation..
Thanks..
Compressed Tries.. This is giving me the correct Compressed Trie, as expected,,,, but there are some issues with it.... And wanted to discuss that....
1) I Build a simple trie first, and then compressed it using a function trie_compress(), Now when i want to add any word into it, it would want a changed trie_add(), also changed trie_lookup(), ok i will do this on my own, just wanted to know, is my approach correct or there could be some better way..
2) In trie_new(), I have used t->substr = (char*)malloc(10);,,,,,, This doesn't look efficient, as memory should be allocated, as in when required. Can we improve upon this.
typedef struct trie
{
int on;
char *substr;
struct trie *first_child;
struct trie *next_sibling;
}trie;
trie* trie_new()
{
trie *t = (trie*)malloc(sizeof(trie));
t->substr = (char*)malloc(10);
t->on = 0;
t->substr[0] = '\0';
t->first_child = NULL;
t->next_sibling = NULL;
return t;
}
trie* trie_at_level(trie *t, char c)
{
while(t != NULL)
{
if(t->substr[0] == c)
{
return t;
}
t = t->next_sibling;
}
return NULL;
}
void trie_add(trie *t, const char *str)
{
const int n = strlen(str);
int i;
for(i=0; i<n; i++)
{
const char c = str[i];
trie* parent = t;
t = t->first_child;
t = trie_at_level(t,c);
if(t == NULL)
{
t = trie_new();
t->substr[0] = c;
t->substr[1] = '\0';
t->next_sibling = parent->first_child;
parent->first_child = t;
}
}
t->on = 1;
}
int trie_lookup(trie *t, const char *str)
{
const int n = strlen(str);
int i;
for(i=0; i<n; i++)
{
const char c = str[i];
t = t->first_child;
t = trie_at_level(t,c);
if(t == NULL)
return 0;
}
return t->on;
}
void trie_compress(trie *t)
{
trie* parent = t;
t = t->first_child;
if(t->first_child != NULL)
trie_compress(t);
if(t->next_sibling == NULL)
{
parent->substr = strcat(parent->substr,t->substr);
parent->first_child = t->first_child;
parent->on = t->first_child->on;
free(t);
return;
}
else
trie_compress(t->next_sibling);
}

Okay, I think I got it right this time around.
Compressed Trie:
#include <string.h>
#include <stdlib.h>
typedef struct trie {
int value;
char* key;
struct trie* kids;
struct trie* next;
} trie;
/* Creates an empty trie.
*/
trie* trie_new () {
trie* t = (trie*) malloc (sizeof (trie));
t->value = 0;
t->key = NULL;
t->kids = NULL;
t->next = NULL;
return t;
}
/* Sets |t->key| to |key|.
*/
static void trie_set_key (trie* t, const char* key) {
char* key_copy = (char*) malloc (sizeof (char) * (strlen (key) + 1));
strcpy (key_copy, key);
free (t->key);
t->key = key_copy;
}
/* Creates a trie with |->key| set to |key| whose |->value| is on.
*/
static trie* trie_new_init (const char* key) {
trie* t = trie_new ();
t->value = 1;
trie_set_key (t, key);
return t;
}
/* Frees all memory used by the trie |t|.
*/
void trie_delete (trie* t) {
if (t == NULL) {
return;
}
trie_delete (t->kids);
trie_delete (t->next);
free (t->key);
free (t);
}
typedef struct trie_str_pair {
trie* trie;
const char* str;
} trie_str_pair;
/* Creates a trie_str_pair with the values |->trie| and |->str| set to
* |t| and |str|, respectively.
*/
static trie_str_pair mk_trie_str_pair (trie* t, const char* str) {
trie_str_pair pair;
pair.trie = t;
pair.str = str;
return pair;
}
/* Tries to find a sibling of |t| or |t| itself that matches the input
* choice function |choiceFunc|. A match occurs if |choiceFunc| returns
* a string other than NULL. Upon a match, the matching trie and the string
* are returned. Otherwise NULL values are returned in the pair struct.
*/
static trie_str_pair lookup_by (
const char* (*choiceFunc)(const char*, trie*)
, const char* key, trie* t
) {
while (t != NULL) {
const char* str = choiceFunc (key, t);
if (str != NULL) {
return mk_trie_str_pair (t, str);
}
t = t->next;
}
return mk_trie_str_pair (NULL, NULL);
}
/* If |prefix| is a prefix of |str|, returns a pointer into |str| immediately
* after the prefix.
*/
static const char* strip_prefix (const char* prefix, const char* str) {
int i;
for (i = 0; prefix [i] != '\0'; ++i) {
if (str [i] != prefix [i]) {
return NULL;
}
}
return str + i;
}
/* If |t->key| is a prefix of |str|, returns a pointer into |str| immediately
* after the prefix.
*/
static const char* strip_prefix_with_key (const char* str, trie* t) {
return strip_prefix (t->key, str);
}
/* If |str| is a prefix of |t->key|, returns a pointer into |t->key|
* immediately after the prefix.
*/
static const char* strip_prefix_from_key (const char* str, trie* t) {
return strip_prefix (str, t->key);
}
/* Returns a pointer into |str1| immediately after the longest common prefix
* between |str1| and |str2|.
*/
static const char* strip_common_prefix (const char* str1, const char* str2) {
int i;
for (i = 0; str1 [i] != '\0' && str2 [i] != '\0'; ++i) {
if (str1 [i] != str2 [i]) {
break;
}
}
if (i == 0) {
return NULL;
}
return str1 + i;
}
/* Returns a pointer into |str| past the longest common prefix between
* |str| and |t->str|.
*/
static const char* strip_common_prefix_on_key (const char* str, trie* t) {
return strip_common_prefix (str, t->key);
}
/* Returns 1 if |key| is in the trie |t|. Returns 0 if not.
*/
int trie_lookup (trie* t, const char* key) {
while (key != NULL && key [0] != '\0') {
trie_str_pair pair = lookup_by (strip_prefix_with_key, key, t->kids);
t = pair.trie;
if (t == NULL) {
return 0;
}
key = pair.str;
}
return t->value;
}
/* Adds |kid| to |t|'s list of kids.
*/
static void trie_add_kid (trie* t, trie* kid) {
kid->next = t->kids;
t->kids = kid;
}
/* Removes |kid| from |t|'s list of kids.
* |kid| must be in |t|'s list of kids.
*/
static void trie_remove_kid (trie* t, trie* kid) {
if (t->kids == kid) {
t->kids = kid->next;
}
else {
t = t->kids;
while (t->next != kid) {
t = t->next;
}
t->next = kid->next;
}
}
/* Replaces |kid| from |t|'s list of kids with |new_kid|.
* |kid| must be in |t|'s list of kids.
*/
static void trie_replace_kid (trie* t, trie* kid, trie* new_kid) {
trie_remove_kid (t, kid);
trie_add_kid (t, new_kid);
}
/* If |t| has exactly one kid and no grandkids, |t| and its kid are merged
* into one trie node. In other words, |t|'s kid's |->key| is appended to
* |t->key| and |t->value| becomes that of its kid's |->value|.
*/
static void trie_try_merge_with_kids (trie* t) {
if (t->key != NULL) {
trie* kid = t->kids;
if (kid != NULL && kid->next == NULL) {
t->value = kid->value;
t->kids = kid->kids;
int new_len = strlen (t->key) + strlen (kid->key);
t->key = realloc (t->key, sizeof (char) * (new_len + 1));
strcat (t->key, kid->key);
free (kid->key);
free (kid);
}
}
}
/* Helper for trie_insert.
*/
static void trie_insert_split_key (
trie* t
, const char* key_prefix, const char* key_suffix
) {
trie* kid = trie_new_init (key_suffix);
trie_add_kid (t, kid);
trie_set_key (t, key_prefix);
}
/* Helper for trie_insert.
*/
static void trie_insert_simple (trie* t, const char* key) {
trie* kid = trie_new_init (key);
trie_add_kid (t, kid);
}
/* Helper for trie_insert.
*/
static void trie_insert_fork (
trie* t
, trie* kid
, char* key_prefix /* Caller loses ownership of this string */
, const char* key_suffix
, const char* kid_key_suffix
) {
trie* fork_kid = trie_new ();
fork_kid->key = key_prefix;
fork_kid->kids = trie_new_init (key_suffix);
fork_kid->kids->next = kid;
trie_replace_kid (t, kid, fork_kid);
fork_kid->next = kid->next;
kid->next = NULL;
trie_set_key (kid, kid_key_suffix);
}
/* Inserts |key| into the trie |t|.
*/
void trie_insert (trie* t, const char* key) {
if (key [0] == '\0') {
return;
}
while (1) {
trie_str_pair pair = lookup_by (strip_prefix_with_key, key, t->kids);
trie* kid = pair.trie;
const char* stripped = pair.str;
if (kid != NULL) {
if (stripped [0] == '\0') {
kid->value = 1;
return;
}
t = kid;
key = stripped;
continue;
}
pair = lookup_by (strip_prefix_from_key, key, t->kids);
kid = pair.trie;
stripped = pair.str;
if (kid != NULL) {
trie_insert_split_key (kid, key, stripped);
return;
}
pair = lookup_by (strip_common_prefix_on_key, key, t->kids);
kid = pair.trie;
stripped = pair.str;
if (kid == NULL) {
trie_insert_simple (t, key);
return;
}
int prefix_len = stripped - key;
char* common_prefix = (char*) malloc (sizeof (char) * (prefix_len + 1));
strncpy (common_prefix, key, prefix_len);
common_prefix [prefix_len] = '\0';
trie_insert_fork (t, kid, common_prefix, stripped, kid->key + prefix_len);
return;
}
}
/* Helper for trie_remove.
*/
static void trie_remove_simple (trie* t, trie* kid) {
trie_remove_kid (t, kid);
free (kid->key);
free (kid);
}
/* Helper for trie_remove.
*/
static void trie_remove_merge (trie* t) {
t->value = 0;
trie_try_merge_with_kids (t);
}
/* Removes |key| from the trie |t|.
*/
void trie_remove (trie* t, const char* key) {
trie_str_pair pair = lookup_by (strip_prefix_with_key, key, t->kids);
trie* kid = pair.trie;
const char* stripped = pair.str;
if (kid == NULL) {
return;
}
if (stripped [0] == '\0') {
if (kid->kids == NULL) {
trie_remove_simple (t, kid);
}
else {
trie_remove_merge (kid);
}
}
else {
trie_remove (kid, stripped);
}
trie_try_merge_with_kids (t);
}

Maybe this would help?
Prefix Tree
Trie C Implementation
Another Trie C Implementation

Related

Cant insert Node to binary tree

I am trying to insert Node to Binary tree. This is my function for creating Node (rest is done).
void BVSCreate_function(TNodef *rootPtr, function_save token) {
TNodef *newPtr = malloc(sizeof(struct tnodef));
if (newPtr == NULL) {
fprintf(stderr, "99");
return;
}
TNodef init;
string initStr;
initStr.str = NULL;
initStr.length = 0;
initStr.alloc = 0;
newPtr = &init;
newPtr->content = &initStr;
newPtr->leftPtr = NULL;
newPtr->rightPtr = NULL;
newPtr->return_type = token.ret_value;
newPtr->parameters = token.param_count;
strCpyStr(newPtr->content, token.content);
rootPtr = newPtr;
}
void BVSInsert_function(TNodef *rootPtr, function_save token) {
if (rootPtr == NULL) {
BVSCreate_function(rootPtr, token);
} else {
if ((strCmpStr(token.content, rootPtr->content)) < 0) {
BVSCreate_function(rootPtr->leftPtr, token);
} else
if ((strCmpStr(token.content, rootPtr->content)) > 0) {
BVSCreate_function(rootPtr->rightPtr, token);
}
}
}
When TNodef and function_save are structs:
typedef struct {
string *content;
int param_count;
int ret_value;
} function_save;
typedef struct tnodef {
string *content;
struct tnodef *leftPtr;
struct tnodef *rightPtr;
int parameters;
int return_type;
} TNodef;
Where string is defined as this struct:
typedef struct {
char *str; // content of string
int length; // length of string
int alloc; // amount of memory allocated
} string;
strCpystr function :
int strCpyStr(string *s1, string *s2) {
int len2 = s2->length;
if (len2 > s1->alloc) {
if (((s1->str) = (char *)realloc(s1->str, len2 + 1)) == NULL) {
return 1;
}
s1->alloc = len2 + 1;
}
strcpy(s1->str, s2->str);
s1->length = len2 + 1;
return 0;
}
I am trying to create a node in binary tree and put there information from struct function_save.
But when I try to print this tree after insert it shows me that tree is still empty.
Your code in BVSCreate_function has undefined behavior because:
newPtr = &init; discards the allocated node and instead uses a local structure that will become invalid as soon as the function returns.
newPtr->content = &initStr; is incorrect for the same reason: you should allocate memory for the string too or possibly modify the TNodeDef to make content a string object instead of a pointer.
Function BVSInsert_function does not return the updated root pointer, hence the caller's root node is never updated. You could change the API, passing the address of the pointer to be updated.
There is also a confusion in BVSInsert_function: it should call itself recursively when walking down the tree instead of calling BVSCreate_function.
Here is a modified version:
/* Allocate the node and return 1 if successful, -1 on failure */
int BVSCreate_function(TNodef **rootPtr, function_save token) {
TNodef *newPtr = malloc(sizeof(*newPtr));
string *newStr = malloc(sizeof(*content));
if (newPtr == NULL || newStr == NULL) {
fprintf(stderr, "99");
free(newPtr);
free(newStr);
return -1;
}
newStr->str = NULL;
newStr->length = 0;
newStr->alloc = 0;
newPtr->content = newStr;
newPtr->leftPtr = NULL;
newPtr->rightPtr = NULL;
newPtr->return_type = token.ret_value;
newPtr->parameters = token.param_count;
strCpyStr(newPtr->content, token.content);
*rootPtr = newPtr;
return 1;
}
int BVSInsert_function(TNodef **rootPtr, function_save token) {
if (*rootPtr == NULL) {
return BVSCreate_function(rootPtr, token);
} else {
if (strCmpStr(token.content, rootPtr->content) < 0) {
return BVSInsert_function(&rootPtr->leftPtr, token);
} else
if ((strCmpStr(token.content, rootPtr->content)) > 0) {
return BVSInsert_function(&rootPtr->rightPtr, token);
} else {
/* function is already present: return 0 */
return 0;
}
}
}
Note also that function strCpyStr may write beyond the end of the allocated area is len2 == s1->alloc, assuming s1->len is the length of the string, excluding the null terminator.
Here is a modified version:
int strCpyStr(string *s1, const string *s2) {
int len2 = s2->length;
if (len2 >= s1->alloc) {
char *newstr = (char *)realloc(s1->str, len2 + 1);
if (newstr == NULL) {
return 1;
}
s1->str = newstr;
s1->alloc = len2 + 1;
}
strcpy(s1->str, s2->str);
s1->length = len2;
return 0;
}

Convert sha256 to smaller uint type

I'm implementing a hash table in c and I chose as key the sha256 hash of the file that I need to store. The problem is that I need to convert the key to a reusable index to insert in the hash table. I tought to rehash the key, but this way I would increase the possibility of overlapping values. Is there a way to use this hash as the key to the table?
The sha256 is store as a BYTE[32] or can be converted as a sting
void* ht_get(ht* table, const char *key) {
size_t index = magicfunction(key);
while (table->entries[index].key != NULL) {
if (strcmp(key, table->entries[index].key) == 0) {
// Found key, return value.
return table->entries[index].value;
}
// Key wasn't in this slot, move to next (linear probing).
index++;
if (index >= table->capacity) {
index = 0;
}
}
return NULL;
}
When I need an absolute minimalist hashmap in C, I usually end up doing something like that:
#include <stddef.h>
#include <string.h>
#include <stdio.h>
struct hmap_entry {
const char *key;
/* Or in your case: */
/* char key[SIZE_OF_SHA256]; */
void *payload;
};
#define HMAP_ENTRY_CNT 256
struct hmap {
struct hmap_entry entries[HMAP_ENTRY_CNT];
};
static size_t str_hash(const char *s) {
size_t hash = 0;
while(*s) {
hash = (hash << 7) ^ (size_t)*s++ ^ hash;
}
return hash;
}
static struct hmap_entry *hmap_search_entry(struct hmap *map
, const char *key)
{
size_t hash = str_hash(key);
/* Or in your case: */
/* size_t hash = 0; memcpy(&hash, key, sizeof(key)) */
hash = hash % HMAP_ENTRY_CNT;
struct hmap_entry *e = NULL;
while(1) {
e = map->entries + hash;
if(e->key == NULL
|| strcmp(key, e->key) == 0) {
break;
}
/* Or in your case: */
/* if(e->key == NULL
|| memcmp(key, e->key, SIZE_OF_SHA256) == 0) {
break;
}
*/
hash = (hash + 1) % HMAP_ENTRY_CNT;
}
return e;
}
And this is how I use it:
int main()
{
struct hmap_entry *e;
struct hmap map = {};
/* insert foo */
e = hmap_search_entry(&map, "foo");
e->key = "foo";
e->payload = "hello world";
/* insert bar */
e = hmap_search_entry(&map, "bar");
e->key = "bar";
e->payload = "Something else";
/* get foo */
e = hmap_search_entry(&map, "foo");
if(e->key) {
printf("Value of \"%s\" is \"%s\"\n", e->key, (const char *)e->payload);
}
else {
printf("Not found!\n");
}
/* get bar */
e = hmap_search_entry(&map, "bar");
if(e->key) {
printf("Value of \"%s\" is \"%s\"\n", e->key, (const char *)e->payload);
}
else {
printf("Not found!\n");
}
/* get test */
e = hmap_search_entry(&map, "test");
if(e->key) {
printf("Value of \"%s\" is \"%s\"\n", e->key, (const char *)e->payload);
}
else {
printf("Not found!\n");
}
return 0;
}

I get a segmentation fault because of free even though i used malloc

i am writing a Generic ADT using C and i keep getting a segmentation fault when i free an element
PairResult pairClear(Pair pair)
{
if(pair == NULL)
{
return PAIR_NULL_ARGUMENT;
}
KeyElement key=pair->key;
DataElement data=pair->data;
if(key)
pair->free_key(key);//i get the Error here
if(data)
pair->free_data(data);
return PAIR_SUCCESS;
}
the memory for key and data is allocated :
Pair pairCreate( KeyElement key, DataElement data,
copyDataElements copy_data,
freeDataElements free_data,
copyKeyElements copy_key,
freeKeyElements free_key)
{
Pair pair = malloc(sizeof(*pair));
if(pair == NULL)
{
return NULL;
}
pair->copy_data=copy_data;
pair->copy_key=copy_key;
pair->free_data=free_data;
pair->free_data=free_key;
KeyElement new_string_key = copy_key(key);
DataElement new_string_data = copy_data(data);
if((new_string_key == NULL) || (new_string_data == NULL))
{
pairDestroy(pair);
return NULL;
}
pair->key = new_string_key;
pair->data = new_string_data;
return pair;
}
this pairDestroy
void pairDestroy(Pair pair)
{
if(pair == NULL)
{
return;
}
#ifndef NDEBUG
PairResult result =
#endif
pairClear(pair);
assert(result == PAIR_SUCCESS);
free(pair);
}
these are the copy functions used:
static KeyElement copyKeyInt(KeyElement n) {
if (!n) {
return NULL;
}
int *copy = malloc(sizeof(*copy));
if (!copy) {
return NULL;
}
*copy = *(int *) n;
return copy;
}
static DataElement copyDataChar(DataElement n) {
if (!n) {
return NULL;
}
char *copy = malloc(sizeof(*copy));
if (!copy) {
return NULL;
}
*copy = *(char *) n;
return (DataElement) copy;
}
and these are the free functions used
static void freeInt(KeyElement n) {
free(n);
}
static void freeChar(DataElement n) {
free(n);
}
and here is the struct of pair
struct Pair_t {
KeyElement key;
DataElement data;
copyDataElements copy_data;
freeDataElements free_data;
copyKeyElements copy_key;
freeKeyElements free_key;
};
these are all the typedef used :
typedef struct Pair_t* Pair;
typedef enum PairResult_t {
PAIR_SUCCESS,
PAIR_OUT_OF_MEMORY,
PAIR_NULL_ARGUMENT,
} PairResult;
typedef void *DataElement;
typedef void *KeyElement;
typedef DataElement(*copyDataElements)(DataElement);
typedef KeyElement(*copyKeyElements)(KeyElement);
typedef void(*freeDataElements)(DataElement);
typedef void(*freeKeyElements)(KeyElement);
and a main function so that u could reproduce it
int main()
{
Pair pair;
for (int i = 1; i < 1000; ++i) {
char j = (char) i;
++j;
pair=pairCreate(&i,&j,copyDataChar,freeChar,copyKeyInt,freeInt);
pairDestroy(pair);
}
I added everything I could for a reproducible code
if anything should be edited please tell me in the comments
Pair pairCreate(...) {
...
pair->free_data = free_data;
pair->free_data = free_key;
// ^^^^^^^^^ UH OH
...
You owe me 15 mins of debugging time.

strdup non-dependent implementation (dumping malloc dependency)

I have a custom implementation for _strdup. It shouldn't have any dependencies, which means I cannot use CRT or anything built-in. The code below works fine. The only problem is that it depends on malloc. Therefore I can't use it with /NODEFAULTLIB, unless I implement my own malloc.
Any ideas for non-dependent implementations? Or at least a malloc/free implementation. I would even accept a shellcode implementation.
size_t __strlen(const char* str)
{
const char* s;
for (s = str; *s; ++s)
;
return (s - str);
}
void* __memcpy(void* to, const void* from, size_t count)
{
register char* f = (char*)from;
register char* t = (char*)to;
register size_t i = count;
while (i-- > 0)
*t++ = *f++;
return to;
}
char* __strdup(const char* str)
{
size_t len;
char* copy;
len = __strlen(str) + 1;
if (!(copy = (char*)malloc(len)))
return nullptr;
__memcpy(copy, str, len);
return copy;
}
I found a broken malloc implementation:
#define MEMORY_CAPACITY 20000
void* mov_sbrk(int increment)
{
static char global_mem[MEMORY_CAPACITY] = { 0 };
static char* p_break = global_mem;
char* const limit = global_mem + MEMORY_CAPACITY;
char* const original = p_break;
if (increment < global_mem - p_break || increment >= limit - p_break)
{
errno = ENOMEM;
return (void*)-1;
}
p_break += increment;
return original;
}
//=======================================================================
#define ALIGNMENT 8
#define ALIGN(size) (((size) + (ALIGNMENT-1)) & ~(ALIGNMENT-1))
typedef struct list_t list_t;
struct list_t
{
unsigned in_use : 1; /* if the block is used or not */
size_t order; /* current order of block (2^order) */
list_t* succ; /* right child block in tree */
list_t* pred; /* left child block in tree */
};
#define K_MAX 22
#define K_MAX_SIZE (1 << K_MAX)
#define ORDER_0 4
// Size of the node metadata
#define META_SIZE (ALIGN(sizeof(list_t)))
static list_t* find_block(size_t);
static size_t get_order(size_t);
static list_t* split(list_t*, size_t);
/* Array of pointers to first block of order k at free_list[k] */
static list_t* freelist[K_MAX + 1];
static void* start = NULL;
static void print_freelist()
{
for (int i = ORDER_0; i <= K_MAX; i++)
{
int f = 0;
int j = 0;
list_t* current = freelist[i];
while (current)
{
if (!current->in_use)
{
f++;
}
j++;
current = current->succ;
}
}
}
void* malloc(size_t requested_size)
{
print_freelist();
if (requested_size <= 0)
{
return NULL;
}
if (!start)
{
// First allocation ever, grab memory and root the tree
start = mov_sbrk(K_MAX_SIZE);
list_t* top = reinterpret_cast<list_t*>(start);
top->order = K_MAX;
top->in_use = 0;
top->succ = NULL;
top->pred = NULL;
freelist[K_MAX] = top;
}
/* E.g. if requested size is 56 bytes, k = 6 (2^6=64)*/
size_t k = get_order(ALIGN(requested_size + META_SIZE));
list_t* r = find_block(k);
if (r) {
r->in_use = 1;
print_freelist();
return (r + 1);
}
else {
return NULL;
}
}
/* Find the smallest power of 2 larger than k */
static size_t get_order(size_t v)
{
int k = ORDER_0;
while ((1 << k) < v) {
k++;
}
return k;
}
// finds a suitable block of order k. if not found return null
static list_t* find_block(size_t k)
{
if (k > K_MAX)
return NULL;
list_t* current = freelist[k];
while (current) {
if (!current->in_use)
return current;
current = current->succ;
}
list_t* big_block = find_block(k + 1);
if (big_block) {
current = split(big_block, k);
}
return current;
}
static void remove_from_freelist(list_t* item)
{
size_t k = item->order;
if (freelist[k] == item)
freelist[k] = item->succ;
if (item->pred)
item->pred->succ = item->succ;
if (item->succ)
item->succ->pred = item->pred;
item->pred = NULL;
item->succ = NULL;
}
static void add_to_freelist(list_t* item)
{
size_t k = item->order;
if (!freelist[k])
{
freelist[k] = item;
item->succ = NULL;
item->pred = NULL;
return;
}
item->pred = NULL;
item->succ = freelist[k];
freelist[k]->pred = item;
freelist[k] = item;
}
static list_t* split(list_t* src, size_t new_order)
{
while (src->order > new_order)
{
/* src becomes left buddy */
remove_from_freelist(src);
// set new order
src->order = src->order - 1;
// calculate half size of old block, aka size of new order.
size_t size = 1 << src->order;
list_t* right = reinterpret_cast<list_t*>(src + size);
right->order = src->order;
right->in_use = 0;
add_to_freelist(right);
add_to_freelist(src);
}
return src;
}
static void merge(list_t* block)
{
if (block->in_use || block->order == K_MAX)
return;
list_t* buddy = (list_t*)((uint64_t)start + (block - start) ^ (1 << block->order));
if (buddy->in_use || buddy->order != block->order)
return;
list_t* left = block;
list_t* right = buddy;
if (block > buddy) {
left = buddy;
right = block;
}
remove_from_freelist(right);
remove_from_freelist(left);
left->order++;
add_to_freelist(left);
merge(left);
}
void free(void* ptr)
{
print_freelist();
if (!ptr)
return;
list_t* block = (((list_t*)ptr) - 1);
block->in_use = 0;
merge(block);
print_freelist();
}
void* calloc(size_t nbr_elements, size_t element_size)
{
size_t size = nbr_elements * element_size;
void* ptr = malloc(size);
if (ptr == NULL)
return NULL;
memset(ptr, 0, size);
return ptr;
}
void* realloc(void* ptr, size_t size)
{
if (!ptr) {
return malloc(size);
}
list_t* block = (((list_t*)ptr) - 1);
if ((1 << block->order) - META_SIZE >= size) {
return ptr;
}
void* new_ptr = malloc(size);
if (!new_ptr) {
return NULL;
}
memcpy(new_ptr, ptr, (1 << block->order) - META_SIZE);
free(ptr);
return new_ptr;
}
Since you have mentioned /nodefaultlib option, seems like you are on Windows. Then instead of using malloc() you can directly use Windows API function HeapAlloc() and then HeapFree() to free copy of the string later. You may want to wrap them into you own __malloc() and __free(), like this:
void* __malloc(size_t size)
{
return HeapAlloc(GetProcessHeap(), 0, size);
}
void __free(void* p)
{
if (p) HeapFree(GetProcessHeap(), 0, p);
}

Insert function for Ternary Search Tree - C

I am new to C and am trying to code up a data structure, primarily, a ternary search tree. I am working under the assumption (for now) that valid char inputs are being passed in. I am having some issues with my insert function. Note that I am also inserting the original string in the last TSTnode where the last character of str will also be held.
Here is what I have so far
struct TSTnode {
char* word; // NULL if no word ends here
char self;
struct TSTnode *left, *sub, *right;
};
int insert_tst(struct TSTnode** tree, const char* str) {
return _insert(tree, str, 0);
}
int _insert(struct TSTnode** tree, const char* str, int position) {
if((*tree) == NULL) {
*tree = new_tst_node(*(str+position));
position = position + 1;
if(*(str+position) == '\0') {
(*tree)->word = strcpy((*tree)->word,str);
return 1;
}
}
else if ((*tree)->self > *(str+position)) {
position = position + 1;
_insert( &((*tree)->left), str, position);
}
else if ((*tree)->self < *(str+position)) {
position = position + 1;
_insert( &((*tree)->right), str, position);
}
else {
position = position + 1;
_insert( &((*tree)->sub), str, position);
}
return 0;
}
struct TSTnode* new_tst_node(char self) {
struct TSTnode* newNode = (struct TSTnode*) malloc(sizeof(struct
TSTnode));
if (newNode == NULL) {
return NULL;
}
newNode->word = NULL;
newNode->self = self;
newNode->left = NULL;
newNode->right = NULL;
newNode->sub = NULL;
return newNode;
}
Here is how I am testing:
struct TSTnode* tree = NULL;
char* words[1] = {"hello"};
for (int i = 0; i < 1; i++) {
if (insert_tst(&tree, words[i]) == 0) {
//print some error
}
else { //success }
EDIT - My issue is that none of my conditional branches are being taken and the insert function simply goes straight to return 0.
Note: You confusingly use tree for both TSTnode* and TSTnode**. I'm going to use tree_ptr for the latter, and pretend that you did the same.
Your claim is false. The body of if((*tree_ptr) == NULL) is executed. You do have a number of problems, though.
You don't handle the case where *tree_ptr == NULL && *(str+position+1) != '\0'.
You don't correctly handle the case where *tree_ptr != NULL && *(str+position+1) == '\0'.
You always return 0 when *tree_ptr != NULL || str[1] != '\0'.
You never allocate word, but you deference it. The thing is, you shouldn't be storing the string again anyway!
You don't handle the case where str[0] == '\0' (empty string).
Fixed:
int insert_tst(struct TSTnode** tree_ptr, const char* str) {
if (!*str)
return 0; /* Zero-length strings are not supported. */
return insert_tst_helper(tree_ptr, str, 0);
}
int insert_tst_helper(struct TSTnode** tree_ptr, const char* str, int position) {
if (*tree_ptr == NULL) {
*tree_ptr = new_tst_node(*(str+position));
if (*tree_ptr == NULL)
return 0; /* Memory allocation error. */
}
if (*(str+position+1) == '\0') { /* If the next char is a NUL */
(*tree_ptr)->is_word = 1;
return 1;
}
else if ((*tree_ptr)->self > *(str+position)) {
position = position + 1;
return insert_tst_helper( &((*tree_ptr)->left), str, position);
}
else if ((*tree_ptr)->self < *(str+position)) {
position = position + 1;
return insert_tst_helper( &((*tree_ptr)->right), str, position);
}
else {
position = position + 1;
return insert_tst_helper( &((*tree_ptr)->sub), str, position);
}
}
Untested.
Let's clean this up, though.
*(str+position)simplifies tostr[position]
ch == '\0'simplifies toch == 0then to!ch
position = position + 1; return insert_tst_helper(..., str, position);simplifies to++position; return insert_tst_helper(..., str, position);then toreturn insert_tst_helper(..., str, position+1);then toreturn insert_tst_helper(..., str+1, 0);then toreturn insert_tst(..., str+1);
Why is recursion being used at all???
Fixed:
int insert_tst(struct TSTnode** tree_ptr, const char* str) {
if (!*str)
return 0; /* Zero-length strings are not supported. */
while (1) {
if (*tree_ptr == NULL) {
*tree_ptr = new_tst_node(*str);
if (*tree_ptr == NULL)
return 0; /* Memory allocation error. */
}
if (!*(str+1)) { /* If the next char is a NUL */
(*tree_ptr)->is_word = 1;
return 1;
}
int cmp = *str - (*tree_ptr)->self;
if (cmp < 0) { tree_ptr = &( (*tree_ptr)->left ); }
else if (cmp > 0) { tree_ptr = &( (*tree_ptr)->right ); }
else { tree_ptr = &( (*tree_ptr)->sub ); }
++str;
}
}
Untested.

Resources