Implement a trie, sans removal.
This commit is contained in:
parent
77123561f0
commit
7afe1a37e4
|
@ -8,7 +8,7 @@ project(libabacus)
|
||||||
|
|
||||||
add_compile_options(-pedantic -Wall)
|
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_executable(libabacus src/main.c)
|
||||||
add_subdirectory(external/liblex)
|
add_subdirectory(external/liblex)
|
||||||
|
|
||||||
|
|
63
include/trie.h
Normal file
63
include/trie.h
Normal 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
92
src/trie.c
Normal 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 ¤t->values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &trie->empty_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void libab_trie_free(libab_trie* trie) {
|
||||||
|
_libab_trie_free(trie->head);
|
||||||
|
trie->head = NULL;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user