Can anyone help me with my binary search tree - c

I'm a computer engineering student and I have to write BST as an assignment but the code is not like what everyone written(so far as I search for some example,so I'm desperate now) Here is my code so far(My classroom use C as a main language not C++)
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct bst_node
{
int data;
struct bst_node *right;
struct bst_node *left;
}BST_NODE;
typedef struct bst
{
int size;
BST_NODE *root;
}BST;
void print(BST_NODE *pos)
{
printf("%d(0)",pos->data);
if(pos->left != NULL)
{
printf("%d(L)\n",pos->left->data);
pos=pos->left;
}
if(pos->right != NULL)
{
printf("%d(R)\n",pos->right->data);
pos=pos->right;
}
if(pos->left != NULL)
print(pos->left);
if(pos->right != NULL)
print(pos->right);
}
int main()
{
int number;
BST b;
BST_NODE *pos;
b.root=NULL;
while(1)
{
scanf("%d",&number);
printf("value=%d",number);
if(number<=0)
break;
if(b.root==NULL)
{
b.root=(BST_NODE*)malloc(sizeof(BST_NODE));
pos=b.root;
pos->data=number;
pos->left=NULL;
pos->right=NULL;
}
else
{
pos=b.root;
while(pos)
{
if(number>pos->data)
{
if(pos->right==NULL)
{
pos->right=(BST_NODE*)malloc(sizeof(BST_NODE));
pos->right->left=NULL;
pos->right->right=NULL;
pos->right->data= number;
pos=pos->right;
}
else
{
pos->right->data= number;
pos=pos->right;
}
}
if(number<pos->data)
{
if(pos->left==NULL)
{
pos->left=(BST_NODE*)malloc(sizeof(BST_NODE));
pos->left->left=NULL;
pos->left->right=NULL;
pos->left->data=number;
pos=pos->left;
}
else
{
pos->left->data=number;
pos=pos->left;
}
}
}
}
}
print(b.root);
return 0;
}
I don't know what wrong with this code because it can only receives 2 value then it stops working. The only thing I found out so far to be a problem is while(pos)loop and I try to fix this for week.I would be grateful,if anyone help me solve this problem. Print it out to would be great.
P.S -stop working mean the windows I run program in just freeze or hang.

You want to break out of your while(pos) loop as soon as you malloc a new node. You are done inserting so stop working.
Also you don't want to overwrite all ->data values while traversing the tree in your else branches.

When you add a value to the tree, it looks like you always replace the existing value with the input number instead of just traversing to the next level. Remove
pos->right->data = number;
And
pos->left->data = numbér;
From main()
You also should add an 'else' before the left node check. As it stands, you're checking the right branch and then the left branch every time through the loop. If you check the right branch and make a hit, you'll always check the left branch, too. Probably not a problem, but unnecessary.
Not sure that's the reason 'it stops working' as 'it stops working' is awful darn vague, but that looks suspicious to me.
Additionally...
Be consistent on your indentation. Sometimes the indentation is more spaces than other times
add spaces between struct definitions and Breen function declarations. Think of these things as chapters in a book. Use the whitespace to make separate things clearly separate.
add a prompt within the loop to indicate that it's expecting input. If you think your app has frozen, it may simply be waiting for input
add a check at the start of print() and sensibly handle null roots. This could occur if you type a negative number as your input the first time around. Missing such a check and typing a negative as your first input may crash.
Oh! And use calloc() instead of malloc(). Calloc initializes new memory to nulls, while malloc does not. Malloc just gives you whatever memory it happens to give you, containing whatever random garbage it may contain. If you use calloc, you will have less liklihood of issues with bad memory.

Related

How to improve recursive function in C?

i have a program with various recursive functions.
I now need to optimize the code to run the program faster: i checked with profiler and, a part from the biggest function with lots of checks, i have two functions that require a lot of time every run.
One (Unmarked_Nodes) is like this:
typedef struct node* tree;
struct node{
char* data;
tree left;
tree right;
int marker;
};
static int remaining = 0;
int main(){
...
}
int Unmarked_Nodes(tree root) {
if (root != NULL) {
Unmarked_Nodes(root->left);
if (root->marker == 0)
remaining++;
Unmarked_Nodes(root->right);
}
return remaining;
}
The other is similar but instead of the if cycle it has a printf of data.
The other, however, is faster than this... why? Or instead: how can i improve the code to make it run faster?
Thanks in advance
Candidate improvements: might help a little although answer remains O(n).
Recurse less often
Loop inside the function for one of the children.
Avoid global
Simply not needed.
Use const
No so much a speed improvement, yet allows for use with constant data.
Avoid hiding pointers
int Unmarked_Nodes(const struct node *root) {
int remaining = 0;
while (root != NULL) {
remaining += Unmarked_Nodes(root->left);
if (root->marker == 0) {
remaining++;
}
root = root->right;
}
return remaining;
}
Perhaps only recurse when both children are non-NULL. Test null-ness at the end of the loop since it is initially false for all recursive entry.
static int Unmarked_Nodes2r(const struct node *root) {
int remaining = 0;
do {
if (root->marker == 0) {
remaining++;
}
if (root->left) {
if (root->right) {
remaining += Unmarked_Nodesr(root->right);
}
root = root->left;
// continue; // Could skip loop test.
} else {
root = root->right;
}
} while (root);
return remaining;
}
int Unmarked_Nodes2(const struct node *root) {
return root ? Unmarked_Nodes2r(root) : 0;
}
In the absence of more information, it would seem that you likely "visit" the tree three times: once for 'marking' nodes (for whatever purpose), once to 'print' marked (or unmarked) nodes, and once more to reset those marks.
Presuming that 'marked nodes' are the interesting ones, consider using a dynamic array of pointers (malloc/realloc in suitable increments) to build a list of only those nodes, print from that list (no 2nd tree traversal), then free() the list (no 3rd tree traversal).
You wouldn't need to 'mark/unmark' anything. Interesting nodes added to the suggested list mean that those nodes are 'marked', and 'unmarked' when the list is erased.
You may need to consider if 'marking' may encounter unwanted duplicates.
Another suggestion is to consider transforming the tree into a list once it is filled. Then, use conventional binary search of that list to mark 'nodes', and a sweep through to erase marks (presuming the same list is to be reused multiple times.
Another suggestion relates to whether you are marking to include or to exclude from the print traversal. If marked nodes are included, then simply 'unmark' them as you print them. If marked nodes are excluded, then mark all those other unmarked nodes being printed that haven't previously been 'excluded' and remember whether '0' means 'marked' or if '1' means marked for the next time it comes to searching/marking.

Segmentation Fault 11, bad variable?

When I compile a source file I receive a segmentation fault: 11 error. I have been able to narrow it down, and I know that the error is coming from this function:
struct drecord { /* use this struct for double-linked lists */
int value;
struct drecord *previous;
struct drecord *next;
};
void sort()
{
struct drecord *currentNode;
struct drecord *end;
for(end=head->previous; end!=NULL && end!=head; end=end->previous)
{
for(currentNode = head; currentNode != NULL && currentNode != end; currentNode = currentNode->next)
{
if (currentNode->value > currentNode->next->value)
{
swap(currentNode, currentNode->next);
}
currentNode = currentNode->next;
}
}
printf("\n");
printf("%d", numElements);
while(numElements > 0)
{
currentNode = head;
printf("Sorted elements: %d", currentNode->value);
delete(currentNode->value);
numElements = numElements - 1;
}
}
void swap(struct drecord *drecord1, struct drecord *drecord2)
{
int aux = drecord1->value;
drecord1->value = drecord2->value;
drecord2->value = aux;
}
Even more specifically, I think that it is coming from the part of the code after printf("\n"), because printf("\n") works but nothing past it does. I had thought that it was a problem with the variable numElements, but I have this same exact code in another source file and it works perfectly. numElements is a global variable. What is wrong?
There are a few issues with your code, but let's focus on the one likely to cause the crash you're seeing:
You call delete(currentNode->value); but isn't value an int? At least, that's how you treat it in your implementation of swap. If it is an int, then what exactly are you deleting?
Perhaps your intent was to delete currentNode, instead. But even that is wrong: please note that that while that will successfully delete currentNode (assuming that it was allocated with new of course), it won't change the head pointer. It will continue to point to where it pointed before: the memory you just called delete on.
So, either way, you're screwed and you should rethink what you're doing in that loop.
As a postscript: while this kind of bug is trivial to find even without a debugger by casual inspection of the code, please invest the time to learn how to use a debugger. It's a critical skill for anyone who wants to program and it will pay dividends: not only will it help you track bugs down, but it will give you a deeper understanding of what is happening and make you a better programmer in the process.

Ternary search trie insert function issues

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.

Find String in BST

I have built a BST that holds album names and years and It constructed according to years.But I want to enter album names and it should give a year.
So I built this code part :
int FindString(treeAlbum *node,char albumTitle[])
{
FindString(node->Left,albumTitle);
FindString(node->Right,albumTitle);
if(!strcpy( node->albumTitle, albumTitle))
{
return node->year;
}
}
And treeAlbum struct
struct treeAlbum{
char albumTitle[100];
int year;
struct treeAlbum *Left;
struct treeAlbum *Right;
}
Finally, This code give an error ( Segmentation Fault). How can I fix this ? Thank You.
My best guess for the segmentation fault is that you aren't checking for your base case.
int FindString(treeAlbum *node,char albumTitle[])
{
if (!node)
{
// Return something sane here
return ERROR_NOT_FOUND;
}
FindString(node->Left,albumTitle);
FindString(node->Right,albumTitle);
if(!strcpy( node->albumTitle, albumTitle))
{
return node->year;
}
}
However, your code has some other issues:
What are you doing with the return values from the recursive calls to FindString. Right now you're not doing anything.
You're using strcpy, but you probably mean strcmp.
You have a binary search tree, but you're doing a post-fix search. This is linear in the size of your tree, but you should be able to use the sorted-ness of the BST to get a log(n) binary tree search. Namely, look at the album at the current node, and see if you're done, should search left, or search right.
The first thing you do in FindString is call FindString again with node->Left. Either node->Left eventually is null (if your tree is correctly constructed) which will cause a segfault or it is an earlier node in the tree (in which case your recursion will cause the stack to fill up). Checking for the null case is certainly required!
You want to use strcmp, not strcpy. You should evaluate the result of two FindString() calls and continue only, when they failed.

The printf functions print something that shouldn't, why?

As you can see from the images attached below, adding the second element from the top of the list create a strange behaviour for the printf function.
the function that add a list node is:
void add_QUEUEnode_top(Item a)
{
if (head==NULL)
{
QUEUEinit(a);
}
else
{
QUEUEput_top(a);
}
return;
}
void QUEUEinit(Item a)
{
head=(link)malloc(sizeof(link*));
head->next=NULL;
head->item=a;
tail=head;
printf("Coda iniziallizata...\n\n");
}
void QUEUEput_top(Item a)
{
link tmp;
tmp=(link)malloc(sizeof(link*));
tmp->item=a;
tmp->next=head;
head=tmp;
return;
}
Here the functions that handle the items:
Item fill_item()
{
Item a;
int i;
for(i=0; i<DIM-1; i++)
{
a.stringa[i]=rand();
}
a.stringa[DIM-1]='\0';
a.numero=rand();
printf("\nOggetto generato: \n");
print_item(a);
return a;
}
void print_item(Item a)
{
printf("\nStringa elemento: ");
printf("%s", a.stringa);
printf("\nNumero elemento: %d\n", a.numero);
}
Here's the link to the codeblock project i'm editing. The function print_item(Item a) that call the "bugged" printf is in the item.c module, while the functions that generate a list item are inside the list.c module.
Any idea of what can cause this problem?
PS: i'm sorry for the captures located in italian
EDIT: definition of the items:
typedef struct
{
char stringa[DIM];
int numero;
} Item;
Definition of the link pointer:
typedef struct QUEUEnode *link;
definition of the link structure:
struct QUEUEnode
{
Item item;
link next;
};
You have several bugs - I'll try to go through and find more of them for you, but the specific problem you're asking about is related to this code:
for(i=0; i<DIM-1; i++)
{
a.stringa[i]=rand();
}
a.stringa[DIM-1]='\0';
You're just putting a random number in each character - many of them may not be interesting or even printable characters in your character set. That's why you get the crazy output you're seeing. If you want to put random printable characters into the string, do so in a more character-set-aware way.
Some more problems:
These allocation lines are wrong:
head=(link)malloc(sizeof(link*));
tmp=(link)malloc(sizeof(link*));
They should be:
head = malloc(sizeof(struct QUEUEnode));
tmp = malloc(sizeof(struct QUEUEnode));
That is, you should allocate enough size for an entire struct QUEUEnode, not just a pointer to one. (Or a pointer to a pointer to one, which is what you had). Hiding the pointer type inside a typedef like you do with typedef struct QUEUEnode *link; is one of those controversial style choices - I personally prefer not to, since it confuses issues like this one pretty fast.
You're passing around a lot of structures by value in this program. That's fine and valid C, it's just a bit non-idiomatic. Normally people pass around pointers instead. If your structure grows to any appreciable size, performance can start to suffer badly as a result of all of the implicit memory copying going on.
You are allocating random text to stringa and then setting numero to a random number. When you print those things you get, well, random output. Because you have not restricted the randomisation to printable characters weird things happen. You are printing control characters. Your second screenshot would indicate that you have printed a carriage return character. I'm sure you don't want to do that!
The program is doing exactly what you asked it to do. Since you did not say what set of characters you wanted to assign to stringa from, I really could not say what your program should be. You could make it choose values in the range A to Z with this change:
a.stringa[i] = 'A' + rand() % 26;
I'll bet that there are other problems with your code, but since the main focus of the question concerned printing, I'll not look any deeper.

Resources