So I'm trying to make a Ternary search trie. Right now, I'm only working on the insert function. I have understood the basic idea of a ternary search trie online. I know that one root node has 3 leaves, and if the character comes before the root, it goes to the left, after - right and if it matches the root, it goes to the middle leaf. So my main objective is to make a program that can suggest words for miss-spelled user entered words. But at the moment I am just working on making the ternary search trie. I use the trie to make a dictionary using which I check user entered words to suggest the next best alternative. But right now, just working on inputting some characters into the ternary trie and when I display it should display it in order.
I am not 100% sure of my logic regarding the middle leaves. Now my program, when run, give me some garbage unlimited values somehow related to the last character entered. I don't know where I've gone wrong. Could someone please point out where I have made my mistake? Also, could you please tell me if any of the logic I've written is wrong? I mean, you don't have to give me the code or anything as I feel I am capable of doing it myself once I understand where I've gone wrong, but if someone could just help me find my mistakes, it would help me a lot!
The WHOLE code :
#include <stdio.h>
#include <stdlib.h> //Because usage of malloc gives warnings without this header
typedef struct tstree
{
struct tstree *lokid;
struct tstree *hikid;
struct tstree *eqkid;
char letter;
}node;
node *head = NULL;
int count = 0;
int insert(char x, node **head)
{
if (*head==NULL) //If it's the first element
{
*head = malloc(sizeof(node));
(*head)->letter = x;
count++;
(*head)->lokid = (*head)->hikid = (*head)->eqkid = NULL; //Assign all 3 to null initially
}
else if ((*head)->letter == x) //If equal, insert below
insert(x , &((*head)->eqkid) );
else if ((*head)->letter > x) //If inserted char comes before current val, insert to left
insert(x,&(*head)->lokid);
else
insert(x,&(*head)->hikid); //Else to the right
return 0;
}
void display(node *head)
{
if(head)
{
display(head->lokid); //print in infix order
printf("%c ",head->letter);
display(head->hikid);
}
//return 0;
}
int main()
{
int op;
char num;
printf("\nWelcome Fabiz. Hope it meets your expectations!\n");
while(1)
{
printf("\n1. To insert an element\n2. Display the tree\n3. Exit\nOption :");
scanf("%d",&op);
switch(op)
{
case 1:
{
system("clear");
printf("\nEnter the element : ");
scanf(" %c",&num);
insert(num,&head);
break;
}
case 2:
{
system("clear");
if(count == 0)
printf("\nEmpty tree\n");
else
{
printf("Display in order..\n");
display(head);
}
break;
}
default: exit(0);
}
}
return 0;
}
I am using Geany text editor and am on Linux Mint. I got a problem one where in the compiler just prints the last character I entered infinitely when I hit the display function.
Any help will be very helpful!
Thanks!
Your display function is wrong. The loop condition never evaluates to false:
while(&(*head)->lokid!=NULL && &(*head)->hikid!=NULL)
This is not what you want. None of &(*head)->lokid or &(*head)->hikid will ever evaluate to NULL. If head is not NULL, then &(*head)->lokid is just the same address as *head plus the offset of lokid in a struct tstree. Note that your loop doesn't even have an update statement that could possibly make the condition false, and it doesn't have any break - it's doomed.
In fact, you don't even need a loop at all. To print it in order, this is all you need:
void display(node *head) {
if (head) {
display(head->lokid);
printf("%c ", head->letter);
display(head->hikid);
}
}
Note that there's no purpose in passing a node ** (I changed that to a node *), and the return value should be void.
UPDATE
Your insert() function is correct, but you use the wrong variable in main. This assignment in the recursion base from insert() is causing unintended behaviour:
temp = *head = malloc(sizeof(node));
Notice that every time you hit the base case, you assign a new node to *head and temp, thus losing reference to whatever was stored in temp before. Then you call display(temp). Yes, you build the trie, but you are printing it starting in the last inserted node - not what you want.
Instead, you should call display with the global variable head, which is the correct root of your trie:
display(head);
The same happens when you call insert. You do not want to insert a new letter starting on the last added node, you want to add it starting it on the root. main() should have this instead:
insert(num, &head);
And while we're at it, note that temp is completely unnecessary. You don't need it. insert manipulates the global head by reference, temp is of no use here (and in fact it introduced a bug).
Changing these 2 lines in main is enough, tested it here, and it's working like a charm.
Related
I'm trying to creating linear linked list recursively with c language,
but keep sticking from here and the code is not working with the error "Linker Tools Error LNK2019". Sadly i can't understand what's the matter. Here is my code.
Thanks for your big help in advance.
#include <stdio.h>
#include <stdlib.h>
struct node
{
char num; //Data of the node
struct node *nextptr; //Address of the next node
};
typedef struct node element;
typedef element *link;
link head;
void displayList(); // function to display the list
int main()
{
char s[] = "abc";
link stol(s);
{
link head;
if (s[0] == '\0')return(NULL);
else {
head = (link)malloc(sizeof(element));
head->num = s[0];
head->nextptr = stol(s + 1);
return(head);
}
}
printf("\n\n Linked List : To create and display Singly Linked List :\n");
printf("-------------------------------------------------------------\n");
displayList();
return 0;
}
void displayList()
{
link tmp;
if (head == NULL)
{
printf(" List is empty.");
}
else
{
tmp = head;
while (tmp != NULL)
{
printf(" Data = %d\n", tmp->num); // prints the data of current node
tmp = tmp->nextptr; // advances the position of current node
}
}
}
You redefine a link object called head in your main() function. It hides the global head variable.
Removing the definition inside main would fix your problem, but you should consider passing a link* as a parameter to your displayList function in any case.
I've just noticed this statement return(head); in main(). You program exits prematurely as a result as well.
Everytime I look at your app, I find more issues. If I were you, I'd start by creating a function that adds a node to the list. It's much easier to add new nodes to the front of the list, so you should try that first. Try adding to the tail once you get this running. Adding to the tail is very similar, but you have to 'walkthe list first to get to the last element, exactly as you already do indisplayList()` Another way is keeping the address of the last node* you've added to the list. Like I said, it adds a bit of complexity, so get it working with addToHead first.
void addToHead(link* l, node* n)
{
n->nextptr = l->nextptr;
l->nextptr = n;
}
in your main, you can allocate one new node at a time, as you already do with malloc(). Initialize its contents num with an integer, and let addToHead deal with the pointer stuff. Your use of pointers is terrible, but lists are quite easy, and addToList pretty much shows what can and what should be put in pointers - namely other pointers.
You can remove almost everything in main() before the first printf. You'll have to
start loop:
write a prompt so the user knows what to do using printf()
read input from user using scanf("%d", &n), or equivalent.
break from the loop if user enters a negative value.
malloc() a new node
set its data num = n
call addToHead to add the node.
Loop until user enters an empty string, or -1.
That should take about 8 to 10 lines of code. if in doubt, you will easily find documentation on scanf, with google or on http://en.cppreference.com/w/c.
I declared a linked list implemented in C as follows:
struct node_List {
int i;
char * name;
struct node_List* next;
};
typedef struct node_List nodeList;
Then I declared the list head globally as:
nodeList list; // head of the list - does not contain relevant data
Finally, I have a function id(char * s) with a string s as th only argument.
nodeType id(char *s)
{
nodeType *p; // another List type
if ((p = malloc(sizeof(nodeType))) == NULL) {
// error: out of memory;
}
nodeList * node = &list;
// printf(" ");
while (node->next != NULL){
node = node->next;
if (strcmp(node->name, s) == 0){
// printf(" ");
// assign node to an attribute in p
return p;
}
}
// error: not found;
}
The problem is, when i run this program and call foo("somestring") the program executes the error: not found part and aborts execution, despite the string somestring being in the list.
I tried executing the very same program by inserting some printf() for debugging purposes, and it works perfectly, except it prints additional characters along with the output.
This happens each time I add some print lines, e.g. if I uncomment the two printf()s which I wrote in the example above (one of them or both, i get the same successful result). It doesn't work though if the printf is called with no arguments or with an empty string "".
I can't figure out what's happening, I double-checked the list creation and population functions and I am totally sure they work correctly. I tried changing the while break condition, but that didn't work, too. I have observed a similar behaviour on both Linux (with gcc) and Windows (using CodeBlocks editor's integrated compiler)
How could a printf directive affect a program so much?
EDIT: This code is part of a syntax analyzer written in Yacc. The whole code can be found below. It's a long read, and it is not completed, but the code above was tested and used to work as explained.
lexer: http://pastebin.com/1TEzzHie
parser: http://pastebin.com/vwCtMhX4
When looking in the provided source code, the algorithm to explore the linked list has two ways to miss node in the while-loop comparison.
Way 1 - starting only from the second node of the list.
Placing node = node->next; before the comparison will force the first comparison to be &(list)->next instead of &(list).
To start from the first node, simply place node = node->next; after
the comparison.
Way 2 - never ending to the last node of the list.
Using (node->next != NULL) in the while condition will force to exit from the loop before comparing the last node => node->next = NULL;.
To end by the last node, simply change the while condition to (node != NULL).
Solution:
while (node != NULL){ // end from the last node
if (strcmp(node->name, s) == 0){
// printf(" ");
// assign node to an attribute in p
return p;
}
node = node->next; // explore link after comparison
}
The actual error is a wrong type declaration of a variable returned by the function:
nodeType* createPoint(char* l){
nodeList* p;
if((p=malloc(sizeof(nodeList))) == NULL){
yyerror("out of memory");
} else {
// do stuff with p
}
return p;
}
The function return value was a nodeType* and p was instantiated as nodeList*.
The declaration of those two types was pretty simple, that's why the program could work.
the working code can be found here.
The strange behaviour with printf() was probably caused by the heap space needed for printf's arguments: since this function accepts an arbitrary number of parameters, it saves them in a list. This list is instantiated in the heap, there overwriting the old data left there from the wrong implementation of createPoint.
I have a problem in inserting string in right position (insert sorting) in linked list. When i add some positions in linked list and end program by typing ' 0 ', program show me only first position.
Also i have doubts about "(strcmp(tmp->ch,new->ch)>0)" it is working as i'm thinking?(compare new element with current (i mean it should be '>' or '<')).
I will be really grateful for any advices ;) .There is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_L 30
typedef struct elem{
char ch[MAX_L];
struct elem *next;
struct elem *prev;
} list_elem;
void add_to_list (list_elem *first, char ch[MAX_L])
{
list_elem *new=(list_elem*)malloc(sizeof(list_elem));
strcpy(new->ch, ch);
list_elem *tmp=first;
do
{
if(tmp->next==NULL)
{
tmp->next=new;
new->prev=tmp;
new->next=NULL;
}
if (strcmp(tmp->ch,new->ch)>0) //guess here should be inserted new element
{
new->prev=tmp->prev;
new->next=tmp;
tmp->prev=new;
}
else
tmp=tmp->next;
}while (tmp->next!=NULL);
}
void print_list(list_elem *first)
{
first=first->next;
if(first->ch==NULL)
printf("lista jest pusta!!\n");
while(first->next!=NULL){
printf("%s\n",first->ch);
first=first->next;}
printf("%s\n",first->ch);
}
int main()
{
list_elem *first=(list_elem*)calloc(1,sizeof(list_elem));
first->next=NULL;
first->prev=NULL;
char a;
char ch[MAX_L];
printf("write ' 0 ' to end program.\n");
printf("write smth to add it to list: \n");
while(ch[0]!='0'){
scanf("%s",&ch);
add_to_list(first,ch);}
print_list(first);
return 0;
}
list_elem *first=(list_elem*)calloc(1,sizeof(list_elem));
How do you know whether calloc succeeded or not?
Check whether first is NULL or not and then only access first->next.
while(ch[0]!='0')
Till this point ch array contains garbage. So how you can compare it with ch[0] with '0'?
scanf("%s",&ch);
%s expects argument of char * type whereas type of &ch is char (*)[30].
Also you may want to avoid the accidental buffer overflow if user enters the string with length > sizeof(ch). Specify maximum field width to remedy that.
first=first->next; in print_list()
Here you just skipped the very first element.
if(first->ch==NULL)
What you really want to do here? Most probably you want to check whether the string first->ch is empty or not. If yes then this is not the way to check that. Instead check first->ch[0] == '\0'
while(ch[0]!='0')
For checking whether user entered 0 or other string, this is incorrect way. This will reject strings starting from 0 (e.g. "0bar")
Correct way would be:
while((ch[0]!='0') || (strlen(ch) > 1))
Break out of the loop once you inserted the new node in the list
if (strcmp(tmp->ch,new->ch)>0)
{
new->prev=tmp->prev;
new->next=tmp;
tmp->prev=new;
}
Here after inserting the new node the if expression strcmp(tmp->ch,new->ch)>0 will remain true in all subsequent loop iterations as we haven't change tmp and new. So this will lead to an infinite loop.
The only exception to this if tmp is the last node.
Solution:
break out of the loop as soon as the new node is inserted into the list.
Just write break; as the last statement in above strcmp if
There's problems in the add_to_list loop :
do {
if(tmp->next==NULL)
{
tmp->next=new;
new->prev=tmp;
new->next=NULL;
break; // you must exit here, you don't want to go the "if" below...
}
if (strcmp(tmp->ch,new->ch)>0)
{
if( tmp->prev != NULL )
{
tmp->prev->next = new; // link from previous to the new element
}
new->prev=tmp->prev;
new->next=tmp;
tmp->prev=new;
break; // you should exit here, work is done
}
else {
tmp=tmp->next;
}
} while (1); // try again
A problem also here:
scanf("%s",&ch); // should be scanf("%s",ch);
And for your question:
Also i have doubts about "(strcmp(tmp->ch,new->ch)>0)" it is working
as i'm thinking?
If you're wrong you'll sort in the reverse order, so it'll be easy to fix.
It looks like when you're inserting before tmp you aren't setting tmp->prev->next to new
For clarity:
if (strcmp(tmp->ch,new->ch)>0) //guess here should be inserted new element
{
new->prev=tmp->prev;
new->next=tmp;
tmp->prev=new;
}
Should be:
if (strcmp(tmp->ch,new->ch)>0) //guess here should be inserted new element
{
tmp->prev->next=new;
new->prev=tmp->prev;
new->next=tmp;
tmp->prev=new;
}
Side note: using new for a variable name is generally frowned upon as it isn't immediately recognizable as a variable since most programmers will have experience in Java/C#/C++ etc. where new is a keyword.
Side note #2: don't cast malloc. I did it until recently when I read this stack thread. It's a very good read.
I wrote an implementation of linked lists (with two points, one for the next value, and one for the previous value) in C language and I'm trying to test my code.
I checked that it scans and prints correctly, however, when I try to test the code I wrote to find a value in list, it returns incorrect output.
The code for find in list is:
node* find_in_list(node *anchor,data_type x)
{
node *temp;
int is_empty=0;
is_empty=is_list_empty(anchor);
if(is_empty)
return NULL;
temp=anchor->next;
while(temp!=NULL)
{
if(temp->data==x)
return temp;
temp=temp->next;
}
return temp;
}
The code to check if the list is empty is
int is_list_empty(node *anchor)
{
int boolean=0;
if(anchor->next=NULL)
boolean=1;
return boolean;
}
It should be noted that anchor never changes. I define anchor as a node in the linked list that does not have an actual value, instead I just use it as a pointer to the first "real" node.
The void main is
#include "linked_list.h"
void main()
{
data_type num;
node *anchor;
anchor=create_node();
scan_list(anchor);
printf("The list scanned is \n");
print_list(anchor);
printf("Enter the number you wish to find\n");
scanf("%d",&num);
printf("The address of %d is\n",num);
printf("%p",find_in_list(anchor,num));
getch();
}
The scanning and printing are done properly. It does indeed print the correct list, but when I try to print the address of some value in the list (no matter what value I enter) it returns 000000.
What is the problem?
I know you've already solved your problem, but ultimately a more straight forward algorithm may have prevented your issue in the first place.
From an elegance/beautiful/simplicity point-of-view, I'd re-write find_in_list() to be something like the following, after eliminating the is_list_empty() routine:
node* find_in_list(node *list,data_type x)
{
for(;list;list=list->next)
if(list->data==x)
break;
return list;
}
(edited to use for-loop)
I wrote the following function which returns the middle element of a linked list, which uses the double pointer method
struct node
{
int data;
struct node *next;
}*start;
void middleelement()
{
struct node *x=start,*y=start;
int n=0;
if(start==NULL)
{
printf("\nThere are no elments in the list");
}
else
{
while((x->next)!=NULL)
{
x=x->next->next;
y=y->next;
n++;
}
printf("\nMiddle element is %d",y->data);
}
}
However, whenever I run the functions, the Windows explorer stops working
What is the flaw in the code?
Is there any better algorithm than this to find the middle element?
If the number of entries is odd, your x will end up being NULL, so when the next loop iteration dreferences it, your program is going to crash. You should modify your condition to account for that:
while(x && x->next) {
...
}
Comparing with NULL is optional in C, so you can skip the != NULL to shorten the condition.
Of course passing the start parameter through a global variable is unorthodox, to say the least. It would be much better to pass it as a regular function parameter.