Implement a trie, sans removal.

This commit is contained in:
Danila Fedorin 2018-03-24 02:01:39 -07:00
parent 77123561f0
commit 7afe1a37e4
3 changed files with 156 additions and 1 deletions

View File

@ -8,7 +8,7 @@ project(libabacus)
add_compile_options(-pedantic -Wall)
add_library(abacus STATIC src/lexer.c src/util.c src/table.c src/parser.c src/libabacus.c src/tree.c src/debug.c src/parsetype.c src/reserved.c)
add_library(abacus STATIC src/lexer.c src/util.c src/table.c src/parser.c src/libabacus.c src/tree.c src/debug.c src/parsetype.c src/reserved.c src/trie.c)
add_executable(libabacus src/main.c)
add_subdirectory(external/liblex)

63
include/trie.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef LIBABACUS_TRIE_H
#define LIBABACUS_TRIE_H
#include "ll.h"
#include "result.h"
/**
* A node in the trie.
*/
struct libab_trie_node_s {
/**
* The "child" node, which points
* to the next layer of the trie, housing
* children that have a prefix ending in this node's key value.
*/
struct libab_trie_node_s* child;
/**
* The "next" node, which points
* to the sibiling of this tree, wich has the same prefix
* as this node.
*/
struct libab_trie_node_s* next;
/**
* The values associated with the key ending with
* this node's key value.
*/
ll values;
/**
* The last letter of the key, which this node represents.
* The remainder of the key is encoded in nodes preceding this one.
*/
char key;
};
/**
* A struct that represents a trie.
*/
struct libab_trie_s {
/**
* The first search node in this trie.
*/
struct libab_trie_node_s* head;
/**
* The empty list returned if no value is found.
* Note that existing nodes return their own linked
* list of values, even if empty. However, for keys
* that don't exist as prefixes in the trie,
* this list is returned to maintain consistency:
* a list is always returned containing the values
* of the trie associated with the given key.
*/
ll empty_list;
};
typedef struct libab_trie_s libab_trie;
typedef struct libab_trie_node_s libab_trie_node;
void libab_trie_init(libab_trie* trie);
libab_result libab_trie_put(libab_trie* trie, const char* key, void* value);
const ll* libab_trie_get(libab_trie* trie, const char* key);
void libab_trie_free(libab_trie* trie);
#endif

92
src/trie.c Normal file
View File

@ -0,0 +1,92 @@
#include "trie.h"
#include <stdlib.h>
#include "util.h"
void libab_trie_init(libab_trie* trie) {
trie->head = NULL;
ll_init(&trie->empty_list);
}
void _libab_trie_free(libab_trie_node* to_free) {
if(to_free == NULL) return;
_libab_trie_free(to_free->next);
_libab_trie_free(to_free->child);
ll_free(&to_free->values);
free(to_free);
}
libab_result _libab_trie_put(libab_trie_node** node, const char* key, void* value) {
libab_result result = LIBAB_SUCCESS;
if((*node = malloc(sizeof(**node)))) {
(*node)->key = *key;
(*node)->next = NULL;
ll_init(&(*node)->values);
if(*(key + 1)) {
result = _libab_trie_put(&(*node)->child, key + 1, value);
} else {
(*node)->child = NULL;
result = libab_convert_ds_result(ll_append(&(*node)->values, value));
}
} else {
result = LIBAB_MALLOC;
}
if(result != LIBAB_SUCCESS) {
free(*node);
*node = NULL;
}
return result;
}
libab_result _libab_trie_add(libab_trie_node* node, void* value) {
return libab_convert_ds_result(ll_append(&node->values, value));
}
libab_result libab_trie_put(libab_trie* trie, const char* key, void* value) {
libab_result result = LIBAB_SUCCESS;
libab_trie_node** current = &trie->head;
char search;
while(*key) {
search = *key;
while(*current && (*current)->key != search) {
current = &(*current)->next;
}
if(*current) {
if(*(key + 1)) {
current = &(*current)->child;
} else {
result = _libab_trie_add(*current, value);
}
key++;
} else {
result = _libab_trie_put(current, key, value);
break;
}
}
return result;
}
const ll* libab_trie_get(libab_trie* trie, const char* key) {
libab_trie_node* current = trie->head;
while(current && *key) {
while(current && current->key != *key) {
current = current->next;
}
if(current == NULL) break;
if(*(key + 1)) {
current = current->child;
key++;
} else {
return &current->values;
}
}
return &trie->empty_list;
}
void libab_trie_free(libab_trie* trie) {
_libab_trie_free(trie->head);
trie->head = NULL;
}