implementing a TRIE data structure - c

Hii ,
i Was implementing a trie in C ... but i am getting an error in the insert_trie function .
I could not figure out why the root node is not getting updated . Please help me with this.
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
typedef struct
{
char value;
int level;
struct node *next;
struct node *list;
}node;
node *trie = NULL;
node *init_trie()
{
node *new = (node *)malloc(sizeof(node));
if(trie == NULL)
{
new->value = '$';
new->next = NULL;
new->list = NULL;
new->level = 0;
trie = new;
printf("\n Finished initializing the trie with the value %c",trie->value);
return trie;
}
printf("\n Trie is already initialized");
return trie;
}
node *insert_trie(char *s)
{
node *nodepointer = trie;
node *new = (node *)malloc(sizeof(node));
node *save = NULL;
int i=0;
while(s[i]!=NULL)
{
nodepointer = nodepointer->list;
while(nodepointer!=NULL)
{
if(s[i] == nodepointer->value)
{
printf("\n Found %c",nodepointer->value);
nodepointer = nodepointer->list;
i++;
}
save = nodepointer;
nodepointer = nodepointer->next;
}
new->value = s[i];
new->next = NULL;
new->list = NULL;
printf("\n Inserting %c",new->value);
save->next = new;
i++;
}
return trie;
}
int main()
{
int num;
char *s = (char *)malloc(sizeof(char)*10);
trie = init_trie();
printf("\n Enter the number of words to enter into the trie ");
scanf("%d",&num);
while(num>0)
{
scanf("%s",s);
//printf("%s",s);
trie = insert_trie(s);
printf("\n Finished inserting the word %s into the trie \n",s);
num --;
}
return 0;
}
I get a segmentation fault due to the line nodepointer = nodepointer->list in insert_trie function ... Why ????
P.S : This is not homework.But i am trying to implement it. I just could not find the mistake .

"Implement a trie with insert, search, and startsWith methods.
Note:
You may assume that all inputs are consist of lowercase letters a-z."
I have written this very simple solution for the above question from LeetCode. It has passed all the 16 test cases from LeetCode. I hope this will help.
//node structure
struct TrieNode {
char value;
int count;
struct TrieNode * children[27];
};
static int count =0;
/** Initialize your data structure here. */
//return root pointer
struct TrieNode* trieCreate() {
struct TrieNode *pNode = NULL;
pNode = (struct TrieNode *)malloc(sizeof(struct TrieNode));
if (pNode)
{
pNode->value = '\0';
pNode->count =0;
memset(pNode->children, 0, sizeof(pNode->children));
}
return pNode;
}
/** Inserts a word into the trie. */
void insert(struct TrieNode* root, char* word) {
struct TrieNode *pCrawl = root;
count ++;
//check if the word is not empty
if(word){
int index=0, i =0;
//check if the root is not empty
if (root){
while( word[i] != '\0'){
index = ( (int) (word[i]) - (int)'a');
if(!pCrawl->children[index])
{
pCrawl->children[index] = trieCreate();
pCrawl->children[index]->value = word[i];
}
pCrawl = pCrawl->children[index];
i++;
}
//Count !=0 tell us that this is the last node;;
pCrawl->count = count;
}
}}
/** Returns if the word is in the trie. */
bool search(struct TrieNode * root, char* word) {
struct TrieNode *pCrawl = root;
bool flag = false;
//check if word is NULL
if(!word)
return false;
//if the trie is empty
if(!root)
{
return false;
}
//if word is empty
if (*word == '\0') {
return true;
}
int i=0, index =0 ;
while (word[i] != '\0')
{
index = ((int) (word[i]) - (int)'a');
//// if the node/character is not in Trie
if(!pCrawl->children[index])
{
flag = false;
break;
}
pCrawl = pCrawl->children[index];
i++;
}
//count != 0 marks node as last / leaf node
if(pCrawl->count != 0 && word[i] == '\0')
{
flag = true;
}
return flag;
}
/** Returns if there is any word in the trie
that starts with the given prefix. */
bool startsWith(struct TrieNode* root, char* prefix) {
struct TrieNode * pCrawl = root;
int i =0, index=0;
bool flag = false;
if(root){
while(prefix[i] != '\0')
{
index = ((int) (prefix[i]) - (int)'a');
if(pCrawl->children[index] == NULL){
flag = false;
return flag;
}
else
flag = true;
pCrawl = pCrawl->children[index];
i++;
}
}
return flag;
}
/** Deallocates memory previously allocated for the TrieNode. */
void trieFree(struct TrieNode* root) {
if(root){
for(int i = 0; i <=26; i ++)
{
trieFree(root->children[i]);
}
free(root);
}
}
// Your Trie object will be instantiated and called as such:
// struct TrieNode* node = trieCreate();
// insert(node, "somestring");
// search(node, "key");
// trieFree(node);

A trie holds one node per character and you're only performing one malloc per string. You should be calling malloc for every node. (Also, malloc.h is outdated. stdlib.h contains malloc since the ANSI C standard of 1989.)

node *insert_trie(char *s)
{
node *nodepointer = trie;
node *new = (node *)malloc(sizeof(node));
node *save = NULL;
int i=0;
while(s[i]!=NULL)
{
nodepointer = nodepointer->list;
while(nodepointer!=NULL)
{
if(s[i] == nodepointer->value)
{
printf("\n Found %c",nodepointer->value);
nodepointer = nodepointer->list; // Advance pointer once OK
i++;
}
save = nodepointer;
nodepointer = nodepointer->next; // Advance pointer without checking
}
new->value = s[i];
new->next = NULL;
new->list = NULL;
printf("\n Inserting %c",new->value);
save->next = new;
i++;
}
return trie;
}
Within the if test you advance nodepointer to nodepointer->list. Once the if test completes you advance nodepointer to nodepointer->next without checking if nodepointer is NULL from the advancement which occured within the if block.

Related

I'm not understanding why my hashTable is not working properly C

I am creating a HashTable in C that uses a Node double pointer and using separate chaining to resolve collisions, but when I run my code it does not place collisions into the linked list.
HTable *createTable(size_t size, int (*hashFunction)(size_t tableSize,
int key),void (*destroyData)(void *data),void (*printData)(void
*toBePrinted)){
HTable * h = malloc(sizeof(HTable));
h->size = size;
h->destroyData = destroyData;
h->hashFunction = hashFunction;
h->printData = printData;
h->table = malloc(h->size * sizeof(Node*));
for(int i = 0; i < h->size; i++){
h->table[i] = malloc(sizeof(Node));
h->table[i]->key = 0;
h->table[i]->data = NULL;
h->table[i]->next = NULL;
}
return h;
}
Node *createNode(int key, void *data){
Node * n = malloc(sizeof(Node));
n->key = key;
n->data = data;
n->next = NULL;
return n;
}
void insertData(HTable *hashTable, int key, void *data){
if(hashTable != NULL){
Node * n = createNode(key, data);
int index = hashTable->hashFunction(hashTable->size, key);
if(hashTable->table[index] != NULL)
if(hashTable->table[index]->key == key){
if(hashTable->table[index]->next != NULL){
n->next = hashTable->table[index]->next;
hashTable->table[index] = n;
}
else
hashTable->table[index] = n;
}
else{
if(hashTable->table[index]->next != NULL){
Node * itr = hashTable->table[index];
while(itr->next != NULL){
itr = itr->next;
}
itr->next = n;
}
else
hashTable->table[index] = n;
}
else{
hashTable->table[index] = n;
}
}
}
and the HTable struck and Node struck look like this:
typedef struct Node
{
int key;
void *data;
struct Node *next;
} Node;
typedef struct HTable
{
size_t size;
Node **table;
void (*destroyData)(void *data);
int (*hashFunction)(size_t tableSize, int key);
void (*printData)(void *toBePrinted);
}HTable;
I am thinking I am running into a problem in my insertData function when I use the iterator to find the last item in the linked list. That or I am misunderstanding the proper use of a double pointer to a node.
I figured out why the data was not chaining. If the keys did not match it would go to the else statement and the first if statement in that block was asking if hashTable->table[index]->next was not NULL when it should have been asking if hashTable->table[index] was NULL. This is because there could have been one node and its next would be pointing to NULL and the data would then have been overridden. Thanks for the responses and i have added comments which was great advice because it helped me find the error. so thank you #wildplasser
Here is the code if anyone is wondering:
void insertData(HTable *hashTable, int key, void *data){
if(hashTable != NULL){
Node * n = createNode(key, data);
int index = hashTable->hashFunction(hashTable->size, key);
//Check if hashTable table node contains data
if(hashTable->table[index]->data != NULL)
//Check if the key at that index matches the incoming key
if(hashTable->table[index]->key == key){
//checks if there is more than one node in the chain and replaces the
//first piece of data in the chain
if(hashTable->table[index] != NULL){
n->next = hashTable->table[index]->next;
hashTable->table[index] = n;
}
}
//if the keys do not match
else{
//check if their is one node in the chain
if(hashTable->table[index] != NULL){
Node * itr = hashTable->table[index];
//iterate through the chain to last node
while(itr->next != NULL){
itr = itr->next;
}
//insert node into end of chain
itr->next = n;
}
}
//if there is no data in the node insert the data
else
hashTable->table[index] = n;
}
}

Linked list only prints the first value of first list

I have a program where three values are inserted into linked lists. When I try to iterate through the list I only get the first value printed. Sorry if the function names are confusing I'm still new to c and I'm trying to use the function and variable names gave me just to make my life easier when taking a test. I'm also pretty unfamiliar with debugger and how I would use it to find out what is going on here. Thanks in advance.
void program_header(char i[]);
Node *allocateNode(int iNewInfo);
Node *searchLL(Node *pHead, int iMatch, Node **ppPrecedes);
Node *insertLL(Node **ppHead, int iNewInfo);
void printLL(Node *pHead);
int main(int argc, char *argv[])
{
program_header(argv[0]);
insertLL(&pHead, 84);
insertLL(&pHead, 45);
insertLL(&pHead, 81);
printLL(pHead);
return 0;
}
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct Node
{
int iInfo;
struct Node *pNext;
}Node;
Node *pHead = NULL;
Node *pNew = NULL;
Node *pPrecedes = NULL;
Node *allocateNode(int iNewInfo)
{
// to allocate a new node
pNew = malloc(sizeof(Node));
if (pNew == NULL)
printf("Memory allocation error");
pNew->iInfo = iNewInfo;
pNew->pNext = NULL;
return pNew;
}
Node *searchLL(Node *pHead, int iMatch, Node **ppPrecedes)
{
Node *p;
for (p = pHead; p != NULL; p = p->pNext)
{
if (iMatch == p->iInfo)
printf("Found! %d\n", iMatch);
return p;
if (iMatch < p->iInfo)
return NULL;
*ppPrecedes = p;
}
return NULL;
}
Node *insertLL(Node **ppHead, int iNewInfo)
{
Node *pFind;
// see if it already exists
pFind = searchLL(*ppHead, iNewInfo, &pPrecedes);
if(pFind != NULL)
return pFind;
// Doesn't already exist. Allocate a node and insert it
pNew = allocateNode(iNewInfo);
if(pPrecedes == NULL)
{ //insert at head
pNew->pNext = *ppHead;
*ppHead = pNew;
}
else
{ //insert after a node
pNew->pNext = pPrecedes->pNext;
pPrecedes->pNext = pNew;
}
return pNew;
}
void printLL(Node *pHead)
{
Node *p;
printf("iInfo Values\n");
for (p = pHead; p != NULL; p = p->pNext)
{
printf("%d\n", p->iInfo);
}
p = pHead;
}
void program_header(char i[])
{
int j, n = strlen(&i[2]);
char *name = &i[2], border[n], dash = '-';
// loads dashes into array
for(j = 0; j < n; j++)
border[j] = dash;
border[j] = '\0';
// print header
printf("\n~%s~\n~%s~\n~%s~\n\n"
, border, name, border);
}
I believe your problem is in your search method. I have reformatted it to show the way that it is currently behaving. To help in making your code more readable and to avoid these type of errors you should get in the habit of using braces in your if statements even if they are only one line.
This is your current code
Node *searchLL(Node *pHead, int iMatch, Node **ppPrecedes)
{
Node *p;
for (p = pHead; p != NULL; p = p->pNext)
{
if (iMatch == p->iInfo)
{
printf("Found! %d\n", iMatch);
}
return p;
if (iMatch < p->iInfo)
{
return NULL;
}
*ppPrecedes = p;
}
return NULL;
}
Notice in the for loop that no matter if a match is found or not you are always returning p which is really pHead. Then in your insert code you are checking to see if the item is found in the list. Since you always return head it thinks that the item is in the list and never adds a new item.
I haven't tested this, but I believe this is the change you would need to make. You are expecting the search to return a node if the value is already in the list. So you want to return p if there is a match, otherwise you want to return NULL:
Node *searchLL(Node *pHead, int iMatch, Node **ppPrecedes)
{
Node *p;
for (p = pHead; p != NULL; p = p->pNext)
{
if (iMatch == p->iInfo)
{
printf("Found! %d\n", iMatch);
return p;
}
if (iMatch < p->iInfo)
{
return NULL;
}
*ppPrecedes = p;
}
return NULL;
}
correct this
Node *allocateNode(int iNewInfo)
{
// to allocate a new node
pNew = malloc(sizeof(Node));
if (pNew == NULL)
printf("Memory allocation error");
pNew->iInfo = iNewInfo;
pNew->pNext = NULL;
return pNew;
}
to this
Node *allocateNode(int iNewInfo)
{
// to allocate a new node
pNew = malloc(sizeof(Node));
if (pNew){
pNew->iInfo = iNewInfo;
pNew->pNext = NULL;
}else{
printf("Memory allocation error");
}
return pNew;
}

C Binary Search Tree insertion

typedef struct word {
char *str;
int freq;
struct word *right;
struct word *left;
} Word;
Word *root = NULL; //global
while(pCounter != NULL){
if(root == NULL){
Word *x = (Word *)malloc(sizeof(Word));
x->str = (char*)malloc(strlen(pCounter->str)+1);
//printf("%s", node->str);
strcpy(x->str,pCounter->str);
x->freq = pCounter->freq;
x->left = NULL;
x->right = NULL;
root = x;
}
else {
Insert(pCounter, root);
}
pCounter = pCounter ->pNext;
}
void * Insert(Word *node, Word *root)
{
printf("inserted%s\n", node->str);
if(root==NULL)
{
Word *x = (Word *)malloc(sizeof(Word));
x->str = (char*)malloc(strlen(node->str)+1);
//printf("%s", node->str);
strcpy(x->str,node->str);
x->freq = node->freq;
x->left = NULL;
x->right = NULL;
return x;
//node = root;
}
else if (strcmp(node->str, root->str)==0){
root -> freq = root->freq+1;
}
else if (strcmp(node->str, root->str)<1){
root->left = Insert(node,root->left);
}
else {
root->right = Insert(node, root->right);
}
return node;
}
void ordered(Word *n){
//printf("ordered");
if(n != NULL){
ordered(n->left);
printf("%-30s %5d\n", n->str, n->freq);
ordered(n->right);
}
}
I'm trying to build a binary search tree to process a linked list into an ordered bst. I can get the output of root to show up correctly but not anything else. It spits out some garbage and i'm not sure why. I set up a printf statement and it shows that it is inserting actual strings. Am i doing something wrong? This isn't all the code but I think it's enough so people can understand what i'm doing. Suggestions?
return node; --> return root; As per BLUEPIXY's comment, this was the correct answer.– BLUEPIXY 2 mins ago

Segmentation Fault (core dumped) in C in Delete() function

i am writing a Dictionary using linked list in C, and all my functions work except my delete function, which is shown below along with all other necessary code. Every time i try to run my program as soon as it reaches a line in which it must delete a node, it gives me the error: Segmentation Fault (core dumped) which means it has something to do with the memory allocation or a null pointer i think. I know that the rest of my code works. All and any help is appreciated! :)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include"Dictionary.h"
// NodeObj
typedef struct NodeObj{
char* key;
char* value;
struct NodeObj* next;
} NodeObj;
// Node
typedef NodeObj* Node;
// newNode()
// constructor of the Node type
Node newNode(char* key, char* value)
{
Node N = malloc(sizeof(NodeObj));
assert(N!=NULL);
// if(key!=NULL && value!=NULL){
N->key = key;
N->value = value;
N->next = NULL;
// }
return(N);
}
// DictionaryObj
typedef struct DictionaryObj{
Node head;
int numItems;
} DictionaryObj;
// newDictionary()
// constructor for the Dictionary type
Dictionary newDictionary(void){
Dictionary D = malloc(sizeof(DictionaryObj));
assert(D!=NULL);
D->head = NULL;
D->numItems = 0;
return D;
}
Node findKey(Dictionary D, char*key){
Node N;
N = D->head;
while(N != NULL){
if(strcmp(N->key,key)==0){
return N;
}
N = N->next;
}
return NULL;
}
char* lookup(Dictionary D, char* k){
if(findKey(D, k)==NULL){
return NULL;
}else{
Node N;
N = findKey(D, k);
return N->value;
}
}
void delete(Dictionary D, char* k)
{
if(lookup(D,k) == NULL){
fprintf(stderr,
"KeyNotFoundException: Cannot delete non-existent key\n");
exit(EXIT_FAILURE);
}
int check = strcmp(D->head->key, k);
if(check == 1){
D->head = D->head->next;
return;
}
Node cur;
Node prev;
cur = D->head;
prev = NULL;
while( cur != NULL){
int ret1;
ret1 = strcmp(cur->key, k);
while( ret1 == 0){
prev = cur;
cur = cur->next;
}
}
prev->next = cur->next;
D->numItems--;
}
The NodeObject should store copy of the string and care for deleting it:
typedef struct Node Node;
struct Node {
Node *next;
char *key, *value;
};
Node* newNode(char* key, char* value) {
assert(key && value);
Node* node = (Node*)malloc(sizeof(Node));
assert(node);
node->next = NULL;
node->key = strdup(key);
node->value = strdup(value);
}
void delNode(Node* node) {
free(node->key);
free(node->value);
}
Consider using the original code (without that strdup) in this scenairo:
Node* prepare() {
char key_buf[20]; strcpy(key_buf, "mykey");
char val_buf[20]; strcpy(val_buf, "myval");
return newNode(key_buf, val_buf);
}
void examine(Node* node) {
printf("Node key=%s value=%s\n", node->key, node->value);
}
int main() {
examine(prepare());
}
the above code would crash because Node would have pointers to stack (in your case without that strdup), but key_buf+val_buf were only valid inside prepare() (garbage outside and therefore inside examine() - node->key points to random data).

anagram detecting using linked lists in c

I'm trying to write a code that'll check 2 words if they are anagrams,using linked lists.To do that,I guess it should receive 2 words from the user and pass every letter they contain to linked list's nodes,and compare the nodes if they have the same letter,if so,remove the same letter from the second word.When the process is done,if the second list is empty,then they are anagrams.Even if 1 letter is not matching,it should return 0,but I don't know how to determine the length of these words,here is what I wrote so far
#include <stdio.h>
#include <stdlib.h>
struct node
{
struct node *prev;
struct node *next;
char data;
};
typedef struct node *NODE,NOD;
NODE last(NODE list)
{
if(list!=NULL)
while(list->next!=NULL)
list=list->next;
NODE lst;
lst=list;
return lst;
}
void insert( char letter, NODE list)
{
NODE nod;
nod=(NODE)malloc(sizeof(NOD));
nod->next=NULL;
nod->prev=NULL;
nod->data=letter;
if(list==NULL)
{
list=nod;
}
else
{
nod->prev=last(list);
last(list)->next=nod;
}
}
Just check that each word has the same number of each letter in it.
int anagrams(const char *a, const char *b) {
int counts[256] = {0};
while (*a) counts[*a++]++;
while (*b) counts[*b++]--;
for (int i = 0; i < 256; i++) {
if (counts[i]) return 0;
}
return 1;
}
Why use linked lists for such an easy problem?
O(N) solution:
Calculate frequencies of every letter for each word and then compare these 2 histograms. If they're equal, then one word can be obtained from another.
If you want to use your linked-list-based solution, then, the length of the word is, indeed:
Length of each input word (they must have the same length) - it can be calculated with a single traversal from the linked list head to the tail.
Amount of removed symbols
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct node {
char data;
struct node *prev;
struct node *next;
} NODE;
NODE *newNode(char ch){
NODE *p = malloc(sizeof(NODE));
if(p){
p->data = ch;
p->prev = p->next = NULL;
}
return p;
}
void insert(NODE **list, NODE *node){
if(*list == NULL){
*list = node;
return ;
}
NODE *curr = *list;
while(curr){
if(curr->data >= node->data){//insert sort
if(curr->prev == NULL)
*list = node;
else
curr->prev->next = node;
node->prev = curr->prev;
curr->prev = node;
node->next = curr;
break;
}
if(curr->next == NULL){
curr->next = node;
node->prev = curr;
break;
} else
curr = curr->next;
}
}
NODE *input_word(){
NODE *word=NULL;
int ch;
while(EOF!=(ch=getchar()) && ch != '\n'){
insert(&word, newNode(ch));
}
return word;
}
bool isAnagram(NODE *word1, NODE *word2){
while(word1 && word2){
if(word1->data != word2-> data)
return false;
word1 = word1->next;
word2 = word2->next;
}
return word1 == NULL && word2 == NULL;
}
int main(){
NODE *word1, *word2;
printf("input word : ");
word1 = input_word();
printf("input other word : ");
word2 = input_word();
if(isAnagram(word1, word2))
printf("YES\n");
else
printf("NO\n");
//drop(word1);drop(word2);
return 0;
}

Resources