linked list – Radix Tree Implementation in c

I tried implementing a radix tree using C language in oder to get the auto complete suggestions of a dictionary. What are the improvements that I can do here. Also, is there any better way of doing this. Thanks in advance.

The text file I used has the following format

a
at
along
bat
cat

Here’s my implementation.

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <ctype.h>

// define a maximum length for the string.
#define MAX_LEN (200)
// define the alphabet size for english.
#define ALPHABET_SIZE (26)

// linked String structure
typedef struct LinkedString {
    // linked string node contains a char.
    char character;
    struct LinkedString *next;

} LinkedString;

// TrieNode structure
typedef struct TrieNode {

    struct TrieNode *children(ALPHABET_SIZE);
    // linked string to place the str inside the trie node.
    LinkedString *LinkedString;
    // boolean to check for leaf_nodes
    bool is_leaf;

} TrieNode;

/* function signatures */

// create a trie Node.
TrieNode *createNode();
// appends to the string(initial: end) and return a linked string.
LinkedString *appendLinkedString(char *str, int inital, int end);
// break the linked string and create a node with the breaked string and returns intial.
TrieNode *breakLinkedString(TrieNode *previousNode, TrieNode *node, LinkedString *breakPoint);
// insert a str to the trie node.
void insert(TrieNode *root, char *str);
// returns the pointer if found the str else returns NULL
TrieNode *searchNodes(TrieNode *root, char *str);
// convert a string in to charactors
int str_to_char(LinkedString *begin, char *str, int initial);
// print suggestions for the prefix.
void printSuggetions(TrieNode *suggestedNode, char str(), int Size);
// create a linked string with a given char.
LinkedString *createString(char Char);

// node count to get the memory used.
int node_count = 0;
// link string count to get the memory.
int link_string_node_count = 0;

int main(){

    char input(MAX_LEN);
    char str(MAX_LEN);
    char lowerCase(MAX_LEN);

    // read the file
    TrieNode *root = createNode();

    // file name of the wordlist
    char *fileName = "wordlist70000.txt";

    // create a file pointer to read the file
    FILE *fptr = fopen(fileName, "r");

    int j = 0;

    // elapsed time ro insert all entries ti the trie
    clock_t start_time = clock();
    // read the file and insert words into the tire
    while (fgets(str, MAX_LEN - 1, fptr))
    {
        j = 0;
        // check whether the character is in alphabet
        for (int i = 0; i < MAX_LEN; ++i){ 

            if (((str(i) > 64) && (str(i) < 91)) || (str(i) > 96) && (str(i) < 123)) {
                // converts the characters into lowercase
                lowerCase(j) = tolower(str(i));
                j++;
            }
            if (str(i) == 'n'|| str(i) == '') {
                break;
            }
        }
        // configure the terminating character
        lowerCase(j) = 0;
        // insert into the trie
        insert(root, lowerCase);
    }
    clock_t end = clock();

    // end the timer
    double elapsedtime = (double)(end - start_time) / CLOCKS_PER_SEC;

   
    printf("nElapsed time for insert: %f sn", elapsedtime);

    while (true){
        // prompt the user to inputs
        printf("Enter the prefix('0' for quit!) :n");

        // get the input
        scanf("%s", input);
        // copy the input to the str
        strcpy(str, input);

        //if the exit condition is met
        if (strcmp(str, "0") == 0){
            printf("Quit! n");
            break;
        }

        j = 0;
        // check whether the character is in alphabet
        for (int i = 0; i < MAX_LEN; ++i){ 

            if (((str(i) > 64) && (str(i) < 91)) || (str(i) > 96) && (str(i) < 123)) {
                // converts the characters into lowercase
                lowerCase(j) = tolower(str(i));
                j++;
            }
            if (str(i) == 'n' || str(i) == '') {
                break;
            }
        }
        // configure the terminating character
        lowerCase(j) = 0;
        strcpy(str, lowerCase);


        // star the time to track the elapsed time
        clock_t start_time = clock();

        // check for the prefix
        TrieNode *suggestedNode = searchNodes(root, str);
        if (!suggestedNode) {
            // if prefix not found
            printf("Prefix Not Found!nn");
            continue;
        }

        printf("n ***************** SUGGETIONS ****************** n");
        printSuggetions(suggestedNode, str, strlen(str));

        // end the timer
        clock_t end = clock();
        // calculate the elapse time
        double elapsedtime = (double)(end - start_time) / CLOCKS_PER_SEC;

        // print the elapsed time and memory used.
        printf("nElapsed time : %f sn", elapsedtime);
        int count1 = (int)sizeof(*(root)) * node_count;
        int count2 = (int)sizeof(LinkedString) * link_string_node_count;
        printf("Memory used : %d Bytesnn", count1 + count2);
    }

    return 0;
}

TrieNode *createNode() {

    node_count++;
    // allocate space for new trie node.
    TrieNode *newtrieNode = (TrieNode *)malloc(sizeof(TrieNode));
    // initialize the linked string with NULL
    newtrieNode->LinkedString = NULL;
    // make it as not a leaf
    newtrieNode->is_leaf = false;

    int i;
    for (i = 0; i < ALPHABET_SIZE; ++i) {
        // make all the chiledrens null.
        newtrieNode->children(i) = NULL;
    }
    return newtrieNode;
}

LinkedString *createString(char Char) {

    link_string_node_count++;
    // allocate space for a new string dynamically.
    LinkedString *newString = (LinkedString *)malloc(sizeof(LinkedString));
    // put the char into its character
    newString->character = Char;
    // make the next pointer null.
    newString->next = NULL;
    // return the new string.
    return newString;
}

LinkedString *appendLinkedString(char *str, int inital, int end) {
    int i;
    // create a pointers to linked strings.
    LinkedString *current = createString(str(inital));
    LinkedString *newString = NULL;
    LinkedString *string = current;
    
    // go from initial position to end position
    for (i = inital + 1; i < end; ++i) {
        // crate a new string with char index i or str
        newString = createString(str(i));
        // make the next pointer point to new string.
        current->next = newString;
        // go through the string
        current = current->next;
    }
    // make the last pointer at the end.
    current = NULL;
    return string;
}

TrieNode *breakLinkedString(TrieNode *previousNode, TrieNode *node, LinkedString *breakPoint) {
    // create a new trie node pointer.
    TrieNode *newNode = createNode();
    // create a new string beginning next to the break point.
    LinkedString *newString = breakPoint->next;
    breakPoint->next = NULL;
    // convert char to index
    int index1 = (newString->character) &mdash; 'a';

    newNode->LinkedString = node->LinkedString;
    node->LinkedString = newString;
    newNode->children(index1) = node;

    int index2 = (newNode->LinkedString->character) - 'a';
    // pointer the new node to the relevent index of the parent node.
    previousNode->children(index2) = newNode;

    // return the newnode.
    return newNode;
}

void insert(TrieNode *root, char *str) {

    // get the length of the str
    int lastLetterIndex = strlen(str);
    int i = 0, charIndex;

    // create trie nodes and likedlist pointers to track
    // previous current and next pointer nodes.
    TrieNode *currentNode = root, *previousNode = NULL;
    TrieNode *newNode = NULL;
    LinkedString *currentLetter, *previousLetter = NULL;
    currentLetter = currentNode -> LinkedString;

    // go till the last leter of the string.
    while (i < lastLetterIndex) {

        charIndex = (str(i)) - 'a';

        // if current letter is null
        if (currentLetter == NULL) {
            
            // if the trie is empty.
            if (currentNode->children(charIndex) == NULL) {
                // create a new node.
                newNode = createNode();
                // append the string(i:lastLetterIndex) point to the new nodes linked
                newNode->LinkedString = appendLinkedString(str, i, lastLetterIndex);
                newNode->is_leaf = true;
                currentNode->children(charIndex) = newNode;
                break;

            } else { // if it is the first node.
                // make the previous node pointing to the current node.
                previousNode = currentNode;
                currentNode = currentNode->children(charIndex);
                previousLetter = currentNode->LinkedString;
                currentLetter = currentNode->LinkedString->next;
            }

        } else {

            if (currentLetter->character != str(i)) {
                // make the current node pointing to the breakedLinkedString.
                currentNode = breakLinkedString(previousNode, currentNode, previousLetter);
                // create a new node.
                newNode = createNode();
                // append the link string to the newNodes LinkedString.
                newNode->LinkedString = appendLinkedString(str, i, lastLetterIndex);
                // make new node a leaf node
                newNode->is_leaf = true;
                // put newNode as a child of a current node.
                currentNode->children(charIndex) = newNode;
                break;

            } else {
                previousLetter = currentLetter;
                currentLetter = currentLetter->next;
            }
        }
        i++;
    }
}


TrieNode *searchNodes(TrieNode *root, char *str) {
    // get the lastIndex of the str
    int lastIndex = strlen(str);
    int i = 0, charIndex;
    TrieNode *currentNode = root;
    LinkedString *currentLetter = currentNode->LinkedString;

    while (i < lastIndex) {

        // get the index from the char Index.
        charIndex = str(i) - 'a';

        // if current letter is null.
        if (currentLetter == NULL) {

            // point the relevent index to the currentNode.
            currentNode = currentNode->children(charIndex);
            // if the word is not found. Then the current node 
            // and the currentLetter is NULL.
            if (!currentNode) return NULL;
            // make the currentLeter pointing to the linked strings next letter.
            currentLetter = currentNode->LinkedString->next;

        } else {
            // go to the next letter.
            currentLetter = currentLetter->next;
        }
        i++;
    }

    // go untilll the current letter is found null
    while (currentLetter != NULL) {
        // go till the end of the character.
        str(lastIndex) = currentLetter->character;
        currentLetter = currentLetter->next;
        lastIndex++;
    }
    // make the last index pointing to the terminating character
    str(lastIndex) = '';
    return currentNode;
}

int str_to_char(LinkedString *begin, char *str, int initial) {

    int newSize = initial;
    LinkedString *currentLetter = begin;

    // go while current lettter is not null
    while (currentLetter != NULL) {
        // put the char by char in str
        str(newSize) = currentLetter->character;
        // goto the next letter
        currentLetter = currentLetter->next;
        newSize++;
    }
    // set the terminating character.
    str(newSize) = '';
    return newSize - 1;
}

void printSuggetions(TrieNode *suggestedNode, char str(), int Size) {

    // create a poiter to the suggested node
    TrieNode *currentNode = suggestedNode;
    int i, j, newSize;

    if (currentNode->is_leaf){
        // go till the word_size
        for (j = 0; j < Size; ++j){
            // print the uppercased char
            printf("%c", toupper(str(j)));
        }
        // print the endline
        printf("n");
    }

    // go through each children node.
    for (i = 0; i < ALPHABET_SIZE; ++i) {

        // if each child is not null
        if (currentNode->children(i) != NULL) {
            // break down the string and get the characters
            newSize = str_to_char(currentNode->children(i)->LinkedString, str, Size);
            // print the suggestion.
            printSuggetions(currentNode->children(i), str, newSize + 1);
        }
    }
}