How to delete a word from tree dictionnary in C? - c

I've implemented a dictionnary in C using tree, this tree stores a word and its definition as followed:
As you can see, some words are sharing same letters.
But now i'd like to implement a delete function but don't know how to proceed ... I know that I should begin to delete the end of the word ...
Here is my code, thank you for your future help !
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct _noeud{
char *value;
struct _noeud *child[26];
}noeud_t;
typedef struct tree{
node_t root;
}Tree;
Tree dict;
int getPos(char letter){
char alpha[26]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
int i;
for(i=0;i<strlen(alpha);i++){
if(alpha[i]==letter){
return i;
}
}
return -1;
}
void addWord(node_t *node, char *word, char *def){
int i;
for(i = 0; i < strlen(word);i++){
int letter=getPos(word[i]);
if(letter==-1){
printf("Unknown letter... \n");
}
node_t *parent = node;
node = node->child[letter];
if(!node){
node = malloc(sizeof(node_t));
parent->child[letter]=node;
}
}
node->value = malloc(strlen(def)+1);
strncpy(node->value,def,strlen(def)),
printf("Word %s added to dictionnary.\n",word);
fflush(stdin);
}
void findWord(node_t *node, char *word){
printf("Looking for word %s \n",word);
int i;
for(i=0;i<strlen(word);i++) {
int letter = getPos(word[i]);
if(NULL ==node->child[letter]){
printf("Unknown word ...\n");
return;
}
else{
node = node->child[letter];
}
}
printf("Word found, its definition is : %s\n",node->value);
}
void deleteWord(node_t *node, char *word){
int i=0;
for(i=0;i<strlen(word);i++) {
//...
}
printf("Word deleted !\n");
}
int main(){
addWord(&dico.root,"dog","it's an animal");
addWord(&dico.root,"pineapple","it's a fruit");
addWord(&dico.root,"car","something to drive");
findWord(&dico.root,"dog");
findWord(&dico.root,"car");
findWord(&dico.root,"pineapple");
deleteWord(&dico.root,"pineapple");
return 0;
}

I can give you an idea on how to solve it, but sorry I didn’t write the code.
So from your code, I can see that you have findWord function, if that works perfectly then use it inside your delete go find the word at this stage you’re pointing to it now you have to think of three possibilities.
If the word that will be deleted doesn’t have any child then delete it with no more complication.
If the word that will be deleted has a single child then make the parent of the word point to the word’s child.
If the word that will be deleted has more than one child then replace the word with one of the children and then delete it.
I hope this will help you

Related

What is wrong with my trie suggestion algorithm?

I am coding an algorithm that uses the trie data structure. Basically, if input is "he", it will return ["hello","help","held","hen",other_words_starting_with_he]. code:
//NOTE: The expression sizeof(array)/sizeof(node) must always evaluate to 26. Not more; not less, for all the node arrays.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *chars="abcdefghijklmnopqrstuvwxyz";
struct node{
char ch;
struct node *next[26];
};
void init_w_null(struct node **n, int len){
register int counter=0;
while(counter<len){
*(n+counter)=NULL;
counter++;
}
}
int index_of_char(char ch){
register int counter=0;
while(*(chars+counter)!='\0'){
if(*(chars+counter)==ch){
return counter;
}
counter++;
}
return -1;
}
void insert(struct node **root, char *key){
if(*root==NULL){
*root=(struct node*)malloc(sizeof(struct node));
if(*root==NULL){
perror("[malloc]");
exit(EXIT_FAILURE);
}
init_w_null((**root).next,26);
struct node *selected=*root;
(**root).ch=key[0];
register int counter=1;
while(counter<strlen(key)){
int ind=index_of_char(key[counter]);
(*selected).next[ind]=(struct node *)malloc(sizeof(struct node));
if(selected==NULL){
perror("[malloc]");
exit(EXIT_FAILURE);
}
(*(*selected).next[ind]).ch=key[counter];
selected=(*selected).next[ind];
counter++;
}
return;
}
register int counter=1;
struct node *selected=*root;
while(counter<=strlen(key)){
int ind=index_of_char(key[counter]);
if((*selected).next[ind]!=NULL){
selected=(*selected).next[ind];
counter++;
continue;
}
(*selected).next[ind]=(struct node*)malloc(sizeof(struct node));
if((*selected).next[ind]==NULL){
perror("[malloc]");
exit(EXIT_FAILURE);
}
(*(*selected).next[ind]).ch=key[counter];
selected=(*selected).next[ind];
init_w_null((*selected).next,26);
counter++;
}
}
void find(struct node *root, char *key){
register int counter=1;
struct node *selected=root;
int ind=0;
while(counter<=strlen(key)){
//if key param ends, and tree doesn't
if(key[counter]=='\0'){
printf("List of possible keys:\n");
construct_str(selected,key);
return;
}
ind=index_of_char(key[counter]);
//a character of key not found.
if((*selected).next[ind]==NULL){
puts("Similar keys not found.");
return;
}
selected=(*selected).next[ind];
counter++;
}
puts("Key found.");
}
void construct_str(struct node *n, char *str){
puts("[construct_str]");
//end of recursion
if(all_children_null(n)&&n!=NULL){
printf("%s\n",str);
return;
}
register int counter=0;
while(counter<26){
if((*n).next[counter]!=NULL){
char nstr[2];
nstr[0]=(*(*n).next[counter]).ch;
nstr[1]='\0';
str=strcat(str,nstr);
construct_str((*n).next[counter],str);
}
counter++;
}
}
int all_children_null(struct node *n){
register int counter=0;
while(counter<26){
if((*n).next[counter]!=NULL){
return 0;
}
counter++;
}
return 1;
}
void insert_full(struct node **arr, char *key){
int first=index_of_char(key[0]);
insert(&arr[first],key);
}
//a debugging function to see whether insertion is successful.
/*void raw_print(struct node *n){
//puts("[raw_print]");
if(n!=NULL){
putchar((*n).ch);
register int counter=0;
for(;counter<26;counter++){
raw_print((*n).next[counter]);
}
if(all_children_null(n)){
printf("\nAll children of %c are NULL.\n",(*n).ch);
}
}
}*/
int main(){
struct node *nds[26];
init_w_null(nds,26);
insert_full(nds,"hello");
insert_full(nds,"help");
insert_full(nds,"bruh");
insert_full(nds,"lmao");
find(nds[index_of_char('l')],"lm");
return 0;
}
output:
List of possible keys:
[construct_str]
Segmentation fault (core dumped)
I've narrowed the problem down to construct_str. Please tell me if I'm wrong, though.
FOR PEOPLE WHO DON'T KNOW WHAT A TRIE IS:
It's a structure which can store strings with the same prefix, so if we add "hello" and "help", the fourth character in both the strings would be siblings. the node of a trie contains a character and a node array with 26 members.
I see that my crystal ball is well attuned today.
Starting with ...
find(nds[index_of_char('l')],"lm");
... you are passing a string literal as the second argument to find(). In that function, a pointer to its first character is associated with parameter key.
Within find(), you are forwarding that pointer to construct_str():
construct_str(selected,key);
, wherein it is associated with parameter str.
In construct_str(), you are passing that pointer as the first argument to strcat():
str=strcat(str,nstr);
strcat appends the contents of the second string to the array containing the first. It does not create a new array for the concatenated result. Therefore, the left pointer must point (in)to an array that
is modifiable, and
contains enough space after the end of the string to accommodate the extra contents.
String literals do not satisfy either criterion. Oops. Undefined behavior results.
In the line
str=strcat(str,nstr);
str is a pointer to a string literal. You are not allowed to modify them. Attempting to modify a string literal using the function strcat will invoke undefined behavior.
When calling strcat, you must ensure that the first argument is pointing to a memory buffer which
you are allowed to write to, and
has sufficient space for adding the character(s) to the string.

Linked list doesn't work as expected

I implemented this code to add an item to the list (it must be a string) and remove a specific string. However it has two problems: FIRST, the order is wrong after insert the nodes to the list. SECOND, after removing a node, it remains a "blank" space, see below when I remove the Third node.
Initial list:
First
Fourth
Third
Second
After list_remove():
First
Fourth
Second
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct myStruct {
char str[20];
struct myStruct * pNext;
};
struct myStruct *list_create(const char *str)
{
struct myStruct *node;
if(!(node=malloc(sizeof(struct myStruct))))
return NULL;
strcpy(node->str, str);
node->pNext = NULL;
return node;
}
int add_to(struct myStruct * list, const char *str)
{
struct myStruct *newnode;
newnode = list_create(str);
newnode->pNext = list->pNext;
list->pNext = newnode;
return 1;
}
char * remove_to(struct myStruct * list, const char *str)
{
while(list->pNext && (strcmp(list->str, str)))
list = list->pNext;
free(list);
return 0;
}
int list_foreach(struct myStruct *node, int(*func)(void*))
{
while(node) {
if(func(node->str)!=0) return -1;
node=node->pNext;
}
return 0;
}
int printstring(void *s)
{
printf("%s\n", (char *)s);
return 0;
}
int main(void)
{
struct myStruct *list;
// Create initial elements of list
list = list_create("First");
add_to(list, "Second");
add_to(list, "Third");
add_to(list, "Fourth");
printf("Initial list:\n");
list_foreach(list, printstring);
putchar('\n');
remove_to(list, "Third");
printf("After list_remove():\n");
list_foreach(list, printstring);
putchar('\n');
return 0;
}
I think I see a few problems:
add_to() always operates on the current list's first item. So every time you add, the new node will be inserted between the first and second (if there is a second).
And the method remove_to does not check if a matching string was actually found. After exhausting the while loop, if not match was found, I think you will free the last item.
C++ has a whole suite of "Collections" and a built in linked list is one of them. Unless this is a homework exercise where you have to implement your own, consider using that.

Transfer char arrays into linked list

I have been hesitant to post a question about this because I'm worried about asking a stupid question, but here it goes:
I am currently trying to create a program that will take whole strings, put them into char arrays and transfer those char arrays to a linked list. I have everything working up to the point of actually putting the arrays into the linked list.
I initially tried to just create each node with the array itself, which was just giving me the first element of the array. Then I found that I need to use strcpy().
I'm not sure what is wrong at this point, but I think it's down to memory allocation because it's giving me a segfault. That is confusing however, because the memory allocation for rach node is already taken care of.
Thank you for any help, this part has been driving me crazy for a few hours now.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 100
struct node {
char info;
struct node *link;
} *start;
void create(char[]);
void display();
void insert_end(char[]);
int main() {
int i;
start=NULL;
char data[SIZE];
printf("Please enter a word: ");
fgets(data, SIZE, stdin);
create(data);
for(i=0; i<5; i++)
{
printf("Please enter a word: ");
fgets(data, SIZE, stdin);
insert_end(data);
}
display();
return 0;
}
void create(char data[])
{
struct node *temp;
temp = (struct node *)malloc(sizeof(struct node));
if (start == NULL)
{
strcpy(temp->info,data);
temp->link=NULL;
start=temp;
}
}
void display()
{
struct node *ptr;
ptr = start;
while (ptr!=NULL)
{
printf("%c", ptr->info);
ptr=ptr->link;
}
}
void insert_end(char data[])
{
struct node *ptr, *tempnode;
ptr = start;
while(1)
{
if(ptr->link != NULL)
{
ptr=ptr->link;
}
else
break;
}
tempnode=(struct node *)malloc(sizeof(struct node));
strcpy(tempnode->info,data);
tempnode->link=NULL;
ptr->link=tempnode;
}
As you stated you are using arrays, space needs to be reserved in the info member of the linked list structure. char type will only hold one character.
struct node {
char info[SIZE];
struct node *link;
} *start;
If info is an array, printf requires %s format modifier.
printf("%s\n", ptr->info);
info is a char not a char *.
Compile with -W -Wall, you'll see most of your mistakes.

storing an array as a linked list in C

I'm working in C and am having some trouble. I need to store an array of chars (string) across a linked list. In other words, convert a string to a linked list. Basically, one character per node. For example string, dog\0, rather then storing a null character in the last node it would just point to a null pointer to signify the end of the string…… d->o->g->NULL
An suggestions would be great, thank you
int main(){
char *string;
string = malloc(sizeof(char)*100);
strcpy(string,"cheese");
node *list = NULL;
list = createNode(string[0]);
int i;
for(i=1;i<strlen(string);i++){
// this is where I'm stuck, the first char 'c'is in,
// I'm guessing i wanna loop through and
// store each char in a new node ?
}
return 0;
}
node *createNode(char data){
node *ptr = malloc(sizeof(node));
if (ptr == NULL)
{
return NULL;
}
ptr->data = data;
ptr->next = NULL;
return ptr;
}
Here is how to do this in C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
node *next;
char data;
};
node *createNode(char data, node *parent) {
node *ptr=(node*)malloc(sizeof(node));
if(ptr==NULL) {
fprintf(stderr, "Memory allocation error.\n");
exit(1);
}
if(parent!=NULL) parent->next=ptr;
ptr->data=data;
ptr->next=NULL;
return ptr;
}
int main() {
char str[]="cheese";
// Store the string to the list
node *first=NULL, *cur=NULL;
for(int i=0, len=strlen(str); i<len; i++) {
cur=createNode(str[i],cur);
if(first==NULL) first=cur;
}
// Now print it out
cur=first;
while(cur!=NULL) {
printf("%c\n", cur->data);
cur=cur->next;
}
_getwch();
return 0;
}
If C++ is OK then here is a working sample:
#include <iostream>
#include <list>
using namespace std;
int main() {
char str[]="cheese", chr;
// Store the string in the list
std::list<char> clist;
for (int i=0, len=strlen(str); i<len; i++)
clist.push_back(str[i]);
clist.push_back('\0');
// Display the list
do {
chr=clist.front();
cout<<chr<<endl;
clist.pop_front();
} while(chr);
_getwch();
return 0;
}

alphabetically sorted binary search tree in c?

how can i develop a program which reads words from a text file and creates an alphabetically sorted binary search tree using those words? here is my code
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
struct treeNode {
char data[20];
int count;
struct treeNode *leftPtr, *rightPtr;
};
int number;
typedef struct treeNode TreeNode;
typedef TreeNode *TreeNodePtr;
void insertNode (TreeNodePtr *treePtr,char word[]);
void alphabetic(TreeNodePtr treePtr);
int main(){
/*reading strings from the file and add them to the tree*/
char first[20];
FILE *fp1;
TreeNodePtr rootPtr=NULL;
int c;
fp1=fopen("output.txt","r");
do{
c=fscanf(fp1,"%s",first);
insertNode(&rootPtr,first);
}while(c!=EOF);
fclose(fp1);
alphabetic(rootPtr);
system("PAUSE");
}
/*for adding nodes to tree*/
void insertNode (TreeNodePtr *treePtr,char word[20]){
TreeNode *temp = NULL;
if(*treePtr == NULL)
{
temp = (TreeNode *)malloc(sizeof(TreeNode));
temp->leftPtr = NULL;
temp->rightPtr = NULL;
temp->data[20] = word[20];
*treePtr = temp;
}
else if(strcmp(word,(*treePtr)->data)<0){
insertNode(&((*treePtr)->leftPtr),word);
}
else if (strcmp(word,(*treePtr)->data)>0){
insertNode(&((*treePtr)->rightPtr),word);
}
else{
number++;
}
}
/*for sorting alphabetically*/
void alphabetic(TreeNodePtr treePtr){
if(treePtr!=NULL){
alphabetic(treePtr->leftPtr);
printf("%3d\n",treePtr->leftPtr);
alphabetic(treePtr->rightPtr);
}
}
when i have a .txt including 4 words my program writes onli four 0' s as output.
This line is wrong:
temp->data[20] = word[20];
It copies a single character from one invalid location to another.
Change it to:
strcpy(temp->data, word);
since you want to copy a string.
Also this line looks wrong:
printf("%3d\n",treePtr->leftPtr);
I'm guessing you want to print the contents of the data string here, so it should be:
printf("%s\n", treePtr->data);
or if you want the integer count element it would be:
printf("%d\n", treePtr->count);

Resources