Cod sursa(job #3131607)

Utilizator enache_albertinaAlbertina Enache enache_albertina Data 20 mai 2023 18:12:55
Problema Trie Scor 0
Compilator c-64 Status done
Runda Arhiva educationala Marime 6.16 kb
/*
    SD 2023 - Trie
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define ALPHABET_SIZE 26
#define ALPHABET "abcdefghijklmnopqrstuvwxyz"

typedef struct trie_node_t trie_node_t;
struct trie_node_t {
    /* Value associated with key (set if end_of_word = 1) */
    void* value;

    /* 1 if current node marks the end of a word, 0 otherwise */
    int end_of_word;

    trie_node_t** children;
    int n_children;
};

typedef struct trie_t trie_t;
struct trie_t {
    trie_node_t* root;
    
    /* Number of keys */
    int size;

    /* Generic Data Structure */
    int data_size;

    /* Trie-Specific, alphabet properties */
    int alphabet_size;
    char* alphabet;

    /* Callback to free value associated with key, should be called when freeing */
    void (*free_value_cb)(void*);

    /* Optional - number of nodes, useful to test correctness */
    int nNodes;
};
trie_node_t* trie_create_node(trie_t * trie) {
    trie_node_t* new_node = (trie_node_t*)malloc(sizeof(trie_node_t));

    new_node->value = NULL;
    new_node->end_of_word = 0;
    new_node->n_children = trie->alphabet_size;
    new_node->children = (trie_node_t**)calloc(trie->alphabet_size, sizeof(trie_node_t));

    trie->nNodes++;

    return new_node;
}

trie_t* trie_create(int data_size, int alphabet_size, char* alphabet, void (*free_value_cb)(void*)) {
    trie_t* trie = (trie_t*)malloc(sizeof(trie_t));

    trie->size = 0;
    trie->data_size = data_size;
    trie->alphabet_size = alphabet_size;
    trie->alphabet = strdup(alphabet);trie->root = trie_create_node(trie);
    trie->free_value_cb = free_value_cb;
    trie->nNodes = 0;

    return trie;
}

void trie_insert(trie_t* trie, char* key, void* value) {
    trie_node_t* current_node = trie->root;

    for(int i = 0; i < strlen(key); ++i) {
        char letter = key[i];

        if(!current_node->children) {
            current_node->children = malloc(ALPHABET_SIZE * sizeof(trie_node_t*));
            for (int j = 0; j < ALPHABET_SIZE; ++j)
                current_node->children[j] = NULL;
        }

        if(!current_node->children[letter - 'a']) {
            current_node->children[letter - 'a'] = trie_create_node(trie);
        }

        current_node = current_node->children[letter - 'a'];
    }

    current_node->end_of_word = 1;
    current_node->value = malloc(trie->data_size);
    memcpy(current_node->value, value, trie->data_size);
    ++trie->size;
}

void* trie_search(trie_t* trie, char* key) {
    trie_node_t* current_node = trie->root;

    for(int i = 0; i < strlen(key); ++i) {
        int char_index = key[i] - 'a';

        if(!current_node->children[char_index]) {
            return NULL;
        }

        current_node = current_node->children[char_index];
    }

    if(current_node != NULL && current_node->end_of_word) {
        return current_node->value;
    }

    return NULL;
}

int delete_helper(trie_t* trie, trie_node_t* node, char* key, int level) {
    if (node) {
        if (level == strlen(key)) {
            if (node->end_of_word) {
                node->end_of_word = 0;

                if (node->children == NULL || node->n_children == 0) {
                    if(trie->free_value_cb && node->value)
                        trie->free_value_cb(node->value);
                    node->value = NULL;
                    trie->nNodes--;
                    return 1;
                }
                return 0;
            }
        } else {
            int char_index = key[level] - 'a';

            if (delete_helper(trie, node->children[char_index], key, level + 1)) {
                free(node->children[char_index]);
                node->children[char_index] = NULL;

                if (!node->end_of_word) {
                    for (int i = 0; i < trie->alphabet_size; ++i) {
                        if (node->children[i]) {
                            return 0;
                        }
                    }

                    trie->nNodes--;
                    return 1;
                }
            }
        }
    }
    
    return 0;
}

void trie_remove(trie_t* trie, char* key) {
    int level = 0;
    if (delete_helper(trie, trie->root, key, level)) {
        free(trie->root->children[key[0] - 'a']);
        trie->root->children[key[0] - 'a'] = NULL;
        trie->root->n_children--;
    }
    
}


void trie_free_node(trie_t* trie, trie_node_t* node) {
    if(!node) {
        return;
    }
    for(int i = 0; i < trie->alphabet_size; ++i) {
        trie_free_node(trie, node->children[i]);
    }

    if(node->value && trie->free_value_cb) {
        trie->free_value_cb(node->value);
    }

    free(node->children);
    free(node);
    trie->nNodes--;
}

void trie_free(trie_t** pTrie) {
    trie_t* trie = *pTrie;

    trie_free_node(trie, trie->root);
    free(trie->alphabet);
    free(trie);

    *pTrie = NULL;
}

/* Needed for Lambda tests, ignore :) */
void cleanup_example_string(char* str) {
    int len = strlen(str);
    
    if(len >= 2 && str[len-2] == '\\') {
        str[len-2] = '\0';
    }
}

int main() {
    int n, value;
    char alphabet[] = ALPHABET;
    char buf[256], key[256], op;
    
    trie_t* trie = trie_create(sizeof(int), ALPHABET_SIZE, alphabet, free);
    
    fgets(buf, 256, stdin);
	sscanf(buf, "%d\n", &n);

    for(int i = 0; i < n; ++i) {
        fgets(buf, 256, stdin);
	    sscanf(buf, "%c", &op);

        if(op == 'i') {
	        sscanf(buf, "%c %s %d\n", &op, key, &value);
            trie_insert(trie, key, &value);
        } else if(op == 'r') {
	        sscanf(buf, "%c %s\n", &op, key);
            cleanup_example_string(key);
            printf("nNodes before removing %s: %d\n", key, trie->nNodes);
            trie_remove(trie, key);
            printf("nNodes after removing %s: %d\n", key, trie->nNodes);
        } else if(op == 's') {
            sscanf(buf, "%c %s\n", &op, key);
            cleanup_example_string(key);

            if(key[0] == '_') {
                key[0] = '\0';
            }

            int* found = trie_search(trie, key);
            printf("%s: ", key[0] == '\0' ? "_" : key);

            if(found) {
                printf("%d\n", *found);
            } else {
                printf("not found\n");
            }
        }
    }

    trie_free(&trie);

    return 0;
}