The problem with my code is that,when a left child value is searched then due do to recursion levels it goes back and checks the right child.And the return gets incorrect. I can't find a way to get past it.
node * search(node *ptr,int key)
{
if(ptr->data==key)
return ptr;
else
{
if(ptr->lchild!='\0')
search(ptr->lchild,key);
else
return '\0';
if(ptr->rchild!='\0')
search(ptr->rchild,key);
else
return '\0';
}
}
Perhaps like this
node * search(node *ptr,int key)
{
node *pwk;
if(ptr == NULL) return NULL;
if(ptr->data==key)
return ptr;
if(NULL!=(pwk=search(ptr->lchild,key)))
return pwk;
if(NULL!=(pwk=search(ptr->rchild,key)))// or return search(ptr->rchild,key);
return pwk;
return NULL;
}
That's right. Try this:
node * search(node *ptr,int key)
{
if(ptr->data==key)
return ptr;
else
{
node *current = NULL;
if(ptr->lchild != NULL)
current = search(ptr->lchild,key);
if(current == NULL) /* not found in the left subtree */
{
if(ptr->rchild != NULL)
current = search(ptr->rchild,key);
}
return current;
}
}
Node *search(Node *ptr, int key)
{
Node *found;
if ( !ptr || ptr->data == key) return ptr;
found = search(ptr->lchild, key);
return (found) ? found : search(ptr->rchild, key);
}
Note: both || and ?: use the short circuit evaluation, which allows me to reduce the number of if(...) conditions to one.
UPDATE: If we are allowed to use the the "crippled ternary" operator gnu-extension, we can also avoid the variable:
Node *search2(Node *ptr, int key)
{
if ( !ptr || ptr->data == key) return ptr;
return search2(ptr->lchild, key) ?: search2(ptr->rchild, key);
}
Adding yet another ternary completely removes the if(...):
Node *search3(Node *ptr, int key)
{
return ( !ptr || ptr->data == key)
? ptr
: search3(ptr->lchild, key) ?: search3(ptr->rchild, key);
}
node * search(node *ptr,int key)
{
Node * p;
// Found the key, return the pointer to the node
if (ptr->data==key)
return ptr;
if (ptr->lchild != NULL)
{
p = search(ptr->lchild,key);
// Found the key, return the pointer to the node
if(p != NULL)
return p;
}
// Didn't find it in the lchild, so search rchild
if (ptr->rchild != NULL)
{
p = search(ptr->rchild,key);
// Found the key, return the pointer to the node
if(p != NULL)
return p;
}
// Not found in left or right child, return NULL
return NULL;
}
Avoid using \0 in this case. \0 is used for a null character. NULL is used for a null pointer. Though both are usually 0, it's preferable to use NULL for pointers. Check this question for more details - What is the difference between NULL, '\0' and 0
Related
I am trying to create a Binary Search Tree (BST) for a really large txt file (around 150000 lines), but my BST is not sorting properly. My current theory is, when I fetch the key from the txt file, it doesn't register properly, making it fetch a random number from memory. Other than that, I have no idea whats wrong.
NOTE: the txt file has the following format (key on left, value on right)
0016718719 #:#-;QZL=!9v
0140100781 5:`ziuiCMMUC
0544371484 W{<_|b5Qd534
0672094320 QcvX=;[lpR("
0494074201 FB[?T5VHc7Oc
0317651971 K`9#Qn{#h]1z
0635368102 KGVm-?hX{Rv7
0107206064 =n1AsY32_.J9
0844660357 L4qL)x{>5e8H
0699014627 v/<4%"sJ4eHR
0786095462 G!cl'YMAL*#S
0067578317 6{"W,j2>#{p*
0730012647 rAi?q<X5NaKT
0715302988 ,8SrSw0rEEc&
0234601050 PRg$$:b|B0'x
0537081097 fgoDc05rc,n|
0226858124 OV##d6th'<us
1059497442 2,'n}YmK,s^i
0597822915 LhicQ#r<Yh\8
0742176394 g`XkLi.>}s+Q
0984120927 DyB:-u*}E&X)
0202768627 8(&zqlPV#DCb
0089402669 tv-vTkn"AIxt
1045610730 hOxZQ<"yyew`
0671297494 )r7gD;:9FHrq
0245267004 f0oO:/Zul0<"
0766946589 n/03!]3t0Lux
0521860458 _D+$,j#YT$cS
0891617938 t%gYiWV17Z/'
0566759626 r2A'PB'xhfw#
0221374897 e[-Nf"#<o9^p
0428608071 46S4!vZA.S&.
0755431241 mgE?2IewG!=g
0534588781 %P|b"_d'VF0S
0030447903 Q&Dow27tkc9+
0957065636 [pHMrM*q*ED7
0739800529 wR;u\Ct/-Vzo
0556668090 =|T.z]?.:DnC
0649777919 2}5M=.u'#1,L
0464018855 x+JImm6w/eG]
0460707117 lxY}\Cdn%!rs
0273053706 s9GmIAE."j|2
0596408906 %'1|R%3tI-Tz
0473143619 k,h&_7rT)?Nb
0922139211 [e0Q1].<Qb;[
0207160144 t!&lXR7`eW#n
0128147823 L,d'7]ZTvPDQ
0178779865 (&--sQ..)7d'
0531711943 4o'^xS6rK]yl
0429655621 eyd7UwKQ][%i
0566959905 k{)d*OH&w2P<
0472331841 DiZF(W"wO42H
0589473577 V0$9-X%YD_kD
0272100993 i%c&R{^#SM$#
0956804045 BtY'cQ){wR{{
0635780805 dWnP0sP2]Tu[
0874803681 swn\*HS08v<w
1027292189 w#E:LaCg(L(I
0592836099 ]&Q({r^(/H%0
0882899568 zb_4acX8E<2-
0542667063 n'xbSaoXArp6
0289624942 G5X#aqr7+*pb
0682188682 H^o)>1\4o5WV
0984355947 =Z{wmP'Z(#2r
0459720821 1vNg_4`3IUUJ
0563538441 uA>QKi]Z31#x
1032927818 $jReN<b/(e{E
0299897321 j=PAkNj#H(L^
0428967901 8lszH<!m\C`w
0668128293 SO("{Rm29l#Y
0354915591 2coM%<Iiwwn<
0672908146 r3VRE;Q3)zi>
0435139431 d_q_)mM"X]N-
0728369037 >X_!}vtc;G(M
0982520682 {h\5gbvzsqGZ
0396776915 $py=A?iNde7(
0511806860 #T+Y0HI9/U6K
0013335601 <$8f|iV\=/RD
0511264736 NFI-#xssP)F*
0727884351 5ZMcmA0[K3P2
0460487630 .D'h(f"LV]#x
0178037927 o3a&fO}="I.S
Here is my Main file:
#include "LAB3BST2.h"
#include <string.h>
#define HEIGHT_WRITTEN 1
#define FINDPARENTHELPER_WRITTEN 1
#define DELETE_WRITTEN 1
#define LOOKUP_written 1
int digit(char *key) {
int number = 0;//create a
while (*key != '\0') {//loop until the end of the string (number)
number = 10 * number + *key - '0';//(10*number) this represents moving the current value of key one up
//(*key - '0') the current char subtracted by '0' or the value of 48
// example: (char '1') - '0' == int 1. Reference ASCII chart to see hexadecimal logic
*key++;
}
return number;
}
int main(void) {
Node *n = NULL; // eliminates compiler warning
FILE *fp;
int c;
Tree *t = NULL;
char *pbuff = (char *)malloc(256);
char *p, *key, *pass;
int temp = 0;
long bst_node = 0;
fp = fopen("IDENTS.txt", "r");
if (!fp) {
printf("File Open Failed\n");
return 0;
}//initialize the head of the tree
while (1) {
p = fgets(pbuff, 256, fp);
if (p == NULL)
break; //memory not allocated, or end of file
while (*p == ' ')
p++; //if spaces, iterate through string
key = p;
p++;
while ((*p) >= 48 && (*p) <= 57)
p++;//if a digit character (47<p<58 or 0-9), iterate through key
*p = '\0';//null everything after the key (digits)
p++; //iterate onto the password
while (*p == ' ')
p++;//if spaces, iterate through string
pass = p;
p++;
while ((*p) != '\r' && (*p) != '\n') {
p++;
}// iterate until the end of the string ('\n')
*p = '\0';//null the rest, and reset "p"
temp = digit(key);
if (temp < 0) {
continue;
}
if (temp == 170696526) {
//nothing
}
if (t == NULL) {
t = initTree(temp, pass);
} else
insert(temp, pass, t->root);//WE NEED TO BE ABLE TO CREATE A PASS THAT DOES NOT CHANGE
bst_node++;
}
printf("\nBST NODES: %ld", bst_node);
fclose(fp);
/*
printf("Original Tree: \n");
printTree(t->root);
printf("\n\n");
if (HEIGHT_WRITTEN == 1) {
printf("Height of tree: %d\n\n", height(t->root));
}
*/
if (DELETE_WRITTEN == 1) {
FILE *fp_del;
fp_del = fopen("DELETES.txt", "r");
while (1) {
p = fgets(pbuff, 256, fp_del);
if (p == NULL)
break;
while (*p == ' ')
p++;
key = p;
p++;
while (*p != '\r' && *p != '\n') {
p++;
}
*p = '\0';
int k = withdraw(digit(key), t->root);
if (k)
bst_node--;
}
}
printf("\nNODES AFTER DELETES: %ld \n", bst_node);
if (!bst_check(t->root))
printf("NOT BST\n");
else
printf("IS A BST\n");
if (LOOKUP_written) {
FILE *fp_look;
fp_look = fopen("LOOKUPS.txt", "r");
int nnkey = 0;
while (1) {
p = fgets(pbuff, 256, fp_look);
if (p == NULL)
break;
while (*p == ' ')
p++;
key = p;
p++;
while (*p != '\r' && *p != '\n') {
p++;
}
*p = '\0';
nnkey = digit(key);
Node* k = find(nnkey, t->root);
if (!k) {
printf("ID: %13d PASSWORD: <NOT FOUND>\n", nnkey);
} else {
printf("ID: %13d PASSWORD: %s\n", nnkey, k->value);
}
}
}
return 0;
}//main()
Here is my function file
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "LAB3BST2.h"
Node *initNode(Key k, char *v)
// Allocate memory for new node and initialize fields.
// Returns pointer to node created.
{
Node *n = malloc(sizeof(Node));
// initialize node if memory obtained
if (n != NULL) {
n->key = k;
n->value = strdup(v);
n->leftChild = NULL;
n->rightChild = NULL;
}
return n;
}//initNode()
Tree *initTree(Key k, char *v)
// Set up new tree. Allocates memory for Tree structure, then
// calls initNode() to allocate first node.
{
Tree *t = malloc(sizeof(Tree));
if (t != NULL)
t->root = initNode(k, v);
return t;
}//initTree()
void printTreeExplanation(void)
// Prints hint to reader what to expect on screen
{
static int done = 0;
if (!done) {
printf("First time explanation of tree display:\n");
printf("Every node is displayed as a comma-separated pair within brackets:");
printf(" (kk,vv)\n");
printf("where kk is the key and vv is the value\n");
printf("A tree starts with a curly bracket { and ends with a curly bracket }.\n");
printf("An empty tree will be {}\n");
printf("A tree with no children will be { (kk,vv),{},{} }\n");
printf("If either subtree is populated, it will be shown using the same ");
printf("technique as described above\n");
printf("(Hint: Start at root - and then match up all the remaining\n");
printf("brackets, then interpret what those bracket pairs are telling\n");
printf("you.)\n============\n\n");
done = 1;
}
}//printTreeExplanation()
void printTree(Node *root)
// Print whole tree. We cannot make it look pretty graphically, so we add some
// characters to make it a little easier to understand. We also don't really
// know what the value field is - it is declared to be a void pointer - so we
// treat it as though it points to an integer.
{
// assume printTree magically knows the types in the tree node
printTreeExplanation();
// start of this tree
printf("{");
// values in the root node (assuming value is pointing to an integer)
printf("(%d,%s),", root->key, root->value);
// Now show left subtree or {} if there is no left subtree
if (root->leftChild != NULL)
printTree(root->leftChild);
else
printf("{}");
// Marker between left and right subtrees
printf(",");
// Now show right subtree or {} if there is no right subtree
if (root->rightChild != NULL)
printTree(root->rightChild);
else
printf("{}");
// Close display of this tree with closing curly bracket
printf("}");
}//printTree()
Node *find(Key k, Node *root)
{
// termination conditions - either true, search is ended
if ((root == NULL) || (root->key == k))
return root;
if (k > root->key) //traverse through the right subtree (larger)
return find(k, root->rightChild);
else //traverse through the right
return find(k, root->leftChild);
}//find()
int insert(Key k, char *v, Node *root)
{
int result = BST_FAIL;
// this if statement can only be true with first root (root of whole tree)
if (root == NULL) {
Node *n = initNode(k, v);
root = n;
return BST_SUCCESS;
}
if (root->key == k)
root->value = strdup(v);//replace password
else
if (k < root->key) {
// key value less than key value in root node - try to insert into left
// subtree, if it exists.
if (root->leftChild != NULL)
// there is a left subtree - insert it
result = insert(k, v, root->leftChild);
else {
// new Node becomes the left subtree
Node *n = initNode(k, v);
root->leftChild = n;
result = BST_SUCCESS;
}
} else
if (k > root->key) { // test actually redundant
// key is greater than this nodes key value, so value goes into right
// subtree, if it exists
if (root->rightChild != NULL)
// there is a right subtree - insert new node
result = insert(k, v, root->rightChild);
else {
// no right subtree - new node becomes right subtree
Node *n = initNode(k, v);
root->rightChild = n;
result = BST_SUCCESS;
}
}
return result;
}//insert()
int intmax(int a, int b) {
return (a >= b) ? a : b;
}//intmax()
int height(Node *root)
// Height definition:
// Height of an empty tree is -1. Height of a leaf node is 0. Height of other
// nodes is 1 more than larger height of node's two subtrees.
{
int nodeheight = -1;
int right, left;// default returned for empty tree
if (root != NULL) {
left = height(root->leftChild);
right = height(root->rightChild);
nodeheight = intmax(left, right);
}
return nodeheight;
}//height()
Node *findParentHelper(Key k, Node *root)
// Help find parent of node with key == k. Parameter root is node with
// at least one child (see findParent()).
{
if (root->leftChild != NULL) {
if (root->leftChild->key == k)
return root;
}
if (root->rightChild != NULL) {
if (root->rightChild->key == k)
return root;
}
if (k > root->key)
return findParentHelper(k, root->rightChild);
else
return findParentHelper(k, root->leftChild);
}//findparenthelper()
Node *findParent(Key k, Node *root)
// root
{
// Deal with special special cases which could only happen for root
// of whole tree
if (root == NULL)
return root;
// real root doesn't have parent so we make it parent of itself
if (root->key == k)
return root;
// root has no children
if ((root->leftChild == NULL) && (root->rightChild == NULL))
return NULL;
// Deal with cases where root has at least one child
return findParentHelper(k, root);
}//findParent()
Node *findMin(Node *root) {
if (root->leftChild == NULL)
return root;
return findMin(root->leftChild);
}
Node *findMax(Node *root) {
if (root->rightChild == NULL)
return root;
return findMax(root->rightChild);
}
int check(Node *p, Node *n) {
if (p->rightChild == n)
return 1; //1==right, 0==left
return 0;
}
void delete(Node *p, Node *n)
// Delete node pointed to by n.
// Parameters:
// n - points to node to be deleted
// p - points to parent of node to be deleted.
{
// Deletion has 3 cases - no subtrees, only left or right subtree, or both
// left and right subtrees.
if (p == n) { //if the root is the node to be deleted
Node *temp;
int key;
char *pass;
if (p->rightChild) {
temp = findMin(p->rightChild);
key = temp->key;
pass = strdup(temp->value);
delete(findParent(temp->key, n), temp);
p->key = key;
p->value = pass;
} else
if (p->leftChild) {
temp = findMax(p->leftChild);
key = temp->key;
pass = strdup(temp->value);
delete(findParent(temp->key, n), temp);
p->key = key;
p->value = pass;
}
return;
}
if (n->leftChild != NULL) { // there is left child
if (n->rightChild) { //if both
Node *temp = findMin(n->rightChild);
n->key = temp->key;
n->value = strdup(temp->value);
delete(findParent(temp->key, n), temp);//delete the min value found (which is a leaf on the left most right branch)
} else { //if only left
if (check(p, n)) {
p->rightChild = n->leftChild;
} else
p->leftChild = n->leftChild;
free(n);
}
} else
if (n->rightChild) { // there is only a right child
if (check(p, n)) {
p->rightChild = n->rightChild;
} else
p->leftChild = n->rightChild;
free(n);
} else {// no children
if (check(p, n)) {
p->rightChild = NULL;
} else
p->leftChild = NULL;
free(n);
}
}//delete()
int withdraw(Key k, Node *root)
// Withdraw does two things:
// return a copy of the node with key k (and value v)
// Delete the node with key k from the tree while ensuring the tree remains valid
{
Node *p, *m;
m = find(k, root);
if (m != NULL) {
// create a copy of the node with the same key and value
//n = initNode(m->key, m->value);
p = findParent(k, root);
// can delete the node
delete(p, m);
return 1;
}
return 0;
}//withdraw()
int bst_check(Node *root) {
if (root == NULL)
return 1; // if on a leaf (return back up to root) //170696526
if (root->leftChild != NULL && root->leftChild->key > root->key)
//if the left child exists and its key is greater than the root
return 0;
if (root->rightChild != NULL && root->rightChild->key < root->key)
// if the right child exists and is smaller than the root
return 0;
if (!bst_check(root->leftChild) || !bst_check(root->rightChild))
//if the check was unsuccessful for both the right and left subtrees
//also recursively checks the left and right child
return 0;
//if all pass, then the tree was a bst
return 1;
}
Here is my function file (.h file):
// LAB3_BST.H
// Header file to be used with code for ELEC278 Lab 3.
//
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef int Key;
#define BST_FAIL 0 // return value when BST function fails
#define BST_SUCCESS 1 // return value when BST function succeeds
// Node in tree has key and pointer to value associated with key.
// Also contains structural components - two pointers to left and
// right subtrees.
typedef struct password {
char *word;
struct password *next;
} pnode;
typedef struct Node {
Key key;
char *value;
struct Node *leftChild, *rightChild;
} Node, pNode;
// Tree is basically pointer to top node in a tree.
typedef struct Tree {
Node *root;
} Tree;
Node *initNode(int k, char *v);
// Create new tree by creating new node with key = k and value = v
// and making it root
Tree *initTree(int k, char *v);
// Find node with key k in tree. Returns pointer to Node if found;
// Returns NULL if not found
Node *find(Key k, Node *root);
// Create new node with key=k, value=v and insert it into tree
// Returns 1 upon success, 0 failure
int insert(int k, char *v, Node *root);
// Print text representation of tree (starting at any Node)
void printTree(Node *root);
// Returns Maximum of two integer numbers
int intmax(int a, int b);
// Find parent of node n where n->key = k
// Returns pointer to parent node if found; Returns NULL if not found
Node *findParent(Key k, Node *root);
// 1. Make copy of node with key=k and returns it
// 2. Delete node with key=k from tree
// Return pointer of node created in 1; Returns NULL if no node
// with specified key value is found
int withdraw(Key k, Node *root);
// Return height of tree (height of specified root)
int height(Node *root);
// Helper function for findParent - see specification in lab
// instructions
Node *findParentHelper(Key k, Node *root);
// Delete node from tree while ensuring tree remains valid
void delete(Node *p, Node *n);
Node* inorder(Node *pn);
int bst_check(Node *root);
I dont know where to start.
There are some problems in function insert:
if the root argument is NULL, the new node is just stored into the argument pointer and BST_SUCCESS is returned. The caller's node variable is not updated. This function should take the address of the Node* as an argument. In your case, the tree is initialized as non empty, so this never occurs, but the tree will become empty after removing all elements and in this case, insert will always fail in spite of returning BST_SUCCESS.
if root->key == k, a new value is allocated for this duplicate key, but the previous value is not freed, hence there is a memory leak.
the test else if (k > root->key) is indeed redundant
Here is a modified and much simpler version:
int insert(Key k, const char *v, Node **np) {
Node *node = *np;
if (node == NULL) {
*np = initNode(k, v);
if (*np == NULL)
return BST_FAIL;
else
return BST_SUCCESS;
}
if (k == node->key) {
// node exists, replace password
char *str = strdup(v);
if (str == NULL) {
return BST_FAIL;
} else {
free(node->value);
node->value = str;
return BST_SUCCESS; // no new node, but insertion successful
}
}
if (k < node->key) {
// key value is less than key value in this node
// insert it into left subtree, creating it if needed.
return insert(k, v, &node->leftChild);
} else {
// key value is greater than key value in this node
// insert it into right subtree, creating it if needed.
return insert(k, v, &node->rightChild);
}
}
Here is a non recursive version:
int insert(Key k, const char *v, Node **np) {
while (*np) {
Node *node = *np;
if (k == node->key) {
// node exists, replace password
char *str = strdup(v);
if (str == NULL) {
return BST_FAIL;
} else {
free(node->value);
node->value = str;
return BST_SUCCESS; // no new node, but insertion successful
}
}
if (k < node->key) {
// key value is less than key value in this node
// insert it into left subtree, creating it if needed.
np = &root->leftChild;
} else {
// key value is greater than key value in this node
// insert it into right subtree, creating it if needed.
np = &root->rightChild;
}
}
*np = initNode(k, v);
if (*np == NULL)
return BST_FAIL;
else
return BST_SUCCESS;
}
Note however that neither of the above functions implement a balanced tree (BST). The tree needs rebalancing if the height of left and right child nodes' heights become too different.
This is not an answer but wanted to add a graph of the input data. I don't see anything out of order (i.e. non-reproducable):
The successor of an element in a BST is the element's successor in the
sorted order determined by the inorder traversal. Finding the
successor when each node has a pointer to its parent node is presented
in CLRS's algorithm textbook (Introduction to Algorithms by MIT
press).
Is there a way to find the first value that is bigger than X without parent in the struct? Like:
typedef struct tree tree;
struct tree{
int value;
tree *left;
tree *right;
};
//Function:
tree *find_first_bigger(tree *t, int x){}
I tried working with:
tree *find_first_bigger(tree *t, int x){
if(t == NULL)
return NULL;
if((*t)->value > x)
find_first_bigger((*t)->left, x);
else if((*t)->value < x)
find_first_bigger((*t)->right), x);
else if((*t)->value == x){
if((*t)->right != NULL)
return tree_first_bigger((*t)->right);
else
return tree;
}
}
With this example(it's using letter but there its not a problem), if I try to search the first bigger than N(It should return me O) but it returns me N.
You have done 90% of the job.Allow me to do the remaining 10%.
Since t is a pointer to structure you should use t->left instead of (*t)->left and same applies while accessing right and value fields of the struct.
Now, Just modify your function as:
Add this as first line of your function
static tree* PTR=NULL;
Modify the second if condition as:
if(t->value > x)
{
PTR=t;
find_first_bigger(t->left, x);
}
Modify the second else if condition as:
else if(t->value == x)
{
if(t->right != NULL)
{
t=t->right;
while(t->left!=NULL)
t=t->left;
return t;
}
else return PTR;
}
Hence the correct function is
tree *find_first_bigger(tree *t, int x)
{
static tree* PTR=NULL;
if(t == NULL)
return NULL;
if(t->value > x)
{
PTR=t;
find_first_bigger(t->left, x);
}
else if(t->value < x)
find_first_bigger(t->right, x);
else if(t->value == x)
{
if(t->right != NULL)
{
t=t->right;
while(t->left!=NULL)
t=t->left;
return t;
}
else return PTR;
}
}
In the main function if pointer returned is NULL, this means that :the key itself is the largest key. Feel free for any queries.
I haven't tested this, but I think it should work. Let me know if it is wrong.
//c++ 11
#include<iostream>
using namespace std;
struct BSTNode{
int val;
BSTNode* left;
BSTNode* right;
};
int FindJustLarger(BSTNode*& node, int token, int sofarlarge){
// for invalid inputs it will return intial value of sofarlarge
// By invalid input I mean token > largest value in BST
if(node == nullptr)
return sofarlarge;
else if(node->val > token){
sofarlarge = node->val;
return FindJustLarger(node->left, token, sofarlarge);}
else
return FindJustLarger(node->right, token, sofarlarge);}
int main(){
BSTNode* head = new BSTNode{5, nullptr, nullptr};
FindJustLarger(head, 5, NULL);
delete head;
return 0;}
Some changes you can do in your code:
You have to return the values from the recursive calls
If the value is not found, return NULL. This means returning NULL if t->right == NULL on the last if.
When going to the left, if the value is not found there, the answer must be the node itself. In the case of N, it is the last node where we turn left: O. If it were P, the answer would be T itself.
After all those changes, the code should look like this:
tree *find_first_bigger(tree *t, int x){
if(t == NULL)
return NULL;
if(t->value > x) {
tree *answer = find_first_bigger(t->left, x);
if (answer != NULL)
return answer;
return t;
} else if(t->value < x) {
return find_first_bigger(t->right, x);
} else if(t->value == x) {
if (t->right != NULL)
return tree_first_bigger(t->right);
return NULL;
}
}
You can find the entire code I used to test in this gist.
In your question, you seemed to indicate that you want to find out InOrderSuccessor() of the the given value 'x'.
If 'x' does not necessarily exist in the tree, we need to change the algorithm. Given the example you provided and the problem statement, here is code for finding the next element in a BST.
The key cases are :
No greater element exists, because 'x' is the biggest.
'x' has a right child ?
YES: get left-most child of x's right sub-tree.
NO : return parent.
Key observation is that we don't update the parent pointer, whenever we go right in the tree.
tree *ptr = root;
tree *prnt = NULL;
while (ptr != NULL) {
if (x == ptr->key) {
if (ptr->right != NULL) {
return GetLeftMostChild(ptr->right);
} else {
return prnt;
}
} else if (x > ptr->key) {
ptr = ptr->right;
} else {
prnt = ptr;
ptr = ptr->left;
}
}
Here is the definition for leftMostChild()
tree *GetLeftMostChild(tree *n) {
tree *ptr = n;
while (ptr->left != NULL) {
ptr = ptr->left;
}
return ptr;
}
I've been trying to get this BST working for the last few days, and I am getting stuck on the search function. The logic seems to be correct (unless I'm missing very important details) but there still is something wrong with the code. Could it be because I am dealing with strings? Anyways, here is some code:
EDIT: I've pinpointed somewhere that seems to be going wrong. It turns out that my root is always null. I placed a printf to test if the NULL-case were true, and it always printed true. I've added my tree initialization at the bottom of this question.
The (Updated) Search Function:
//Thank you, M Oehm
node* search(node * tree, char *key)
{
/* char *key is user input */
int cmp;
if(tree == NULL) {
return NULL;
}
cmp = strcmp(key, tree->key);
if(cmp < 0) return search(tree->left, key);
if(cmp > 0) return search(tree->right, key);
return tree;
}
Implementation in main function:
printf("Enter a string to search the tree with: ");
fgets(findNode, MAX_WORD, stdin);
findString = malloc(sizeof(char)*strlen(findNode)+1);
strcpy(findString,findNode);
printf("findString: %s\n", findString);
searched = search(&root, findString);
if(searched == NULL) {
printf("No_such_key\n");
free(findString);
}
else {
printNode(searched);
free(findString);
}
break;
Tree Initialization (via file parsing):
/* Loop through each line in the file*/
while(fgets(buffer, sizeof(buffer), file) != NULL) {
tempToken = strtok(buffer, " \n");
while(tempToken != NULL) {
/* Assign default values */
curr = (node *)malloc(sizeof(node));
curr->left = curr->right = NULL;
curr->key = malloc(sizeof(char)*strlen(tempToken)+1); /* +1 for '\0' */
strcpy(curr->key, tempToken);
curr->frequency = 1;
/* Insert node into tree */
insert(&root, curr);
/* Get next token */
tempToken = strtok(NULL, " \n");
}
}
/* Test insertion worked; close file */
print_inorder(root);
fclose(file);
Insertion Function:
void insert(node ** tree, node * item)
{
/* If no root, item is root */
if(!(*tree)) {
*tree = item;
return;
}
/* If item value is less than node in tree, assign to left */
if(strcmp(item->key,(*tree)->key) < 0) {
insert(&(*tree)->left, item);
}
else if(strcmp(item->key,(*tree)->key) > 0) {
insert(&(*tree)->right, item);
}
else if(strcmp(item->key,(*tree)->key) == 0) {
(*tree)->frequency++;
}
}
The print function shows me that the insertion works properly.
There are two errors in your code: You don't check whetehr the root node, to which you pass a pointer, is null and you don't return the results from the recursive functions.
Your function doesn't modify the tree, so you don't have to pass a pointer to the nodes. That method is useful for functions that modify the tree, e.g. for inserting or deleting nodes. Your function shoul pass a pointer to the root node. That also signals to the user that the tree won't be modified.
So here's a corrected version:
node* search(node *tree, const char *key)
{
int cmp;
if (tree == NULL) return NULL;
cmp = strcmp(key, tree->key);
if (cmp < 0) return search(tree->left, key);
if (cmp > 0) return search(tree->right, key);
return tree;
}
That version must be called like this:
node *hit = search(tree, "bingo!");
Note that this function does the string comparison only once and saves the result in a temporary variable. Your code calls strcmp up to three times.
You don't have to use recursion here. It's even a bit wasteful, because you have to percolate the answer up the first call. Recursion is useful when each step has to maintain a state, which you can represent as local variables. Here, you just change the input node.
Here's a non-recursive variant of the search function:
node* search(node *tree, const char *key)
{
while (tree) {
int cmp = strcmp(key, tree->key);
if (cmp == 0) return tree;
tree = (cmp < 0) ? tree->left : tree->right;
}
return NULL;
}
search(&(*tree)->left, key);
Should be:
return search(&(*tree)->left, key);
Same for the right case.
Try changing your function to something like this.
node* search(node * tree, char * key)
{
if(tree == NULL) {
return NULL;
}
if(strcmp(key,tree->key) < 0) {
return search(tree->left, key);
}
else if(strcmp(key,tree->key) > 0) {
return search(tree->right, key);
}
printf("Success!\n");
return tree;
}
A simple node* would suffice for your problem. No need for double pointers.
i am trying to write a program that will do the following
-read a file from std in
-read each line, and add each line to a binary tree
*if name is already in binary tree,dont add the name to the tree again but update its count of repititions
-print out the binary tree
the file being read in looks something like
dylan
bob
dylan
randall
randall
so when i print out the binary tree i would like it to print out
bob 1
dylan 2
randall 2
i was able to successfully print out the names without worrying about repetitions. I have commented out the blocks of code that mess my program up which is anything interacting with my search function that i added after the fact to take care of repetitions. The code builds a binary tree with each "leave" being a structure of 4 parts,the name,thecount,and the pointers to left and right childs.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char* name;
int count;
struct node* left;
struct node* right;
};
struct node* addNode(char* string);
void insert(struct node *root, char* stringgg);
void preorder(struct node *root);
int search(struct node* leaf,char* string2find);
int main()
{
char buffer[20];
struct node *root = NULL;
while( fgets(buffer, sizeof(buffer), stdin) != NULL )
{
if(root == NULL)
root = addNode(buffer);
else
insert(root,buffer);
}
preorder(root);
}
struct node* addNode(char* string)
{
struct node *temp = malloc(sizeof(struct node));
temp->name = malloc(strlen(string) + 1);
strcpy(temp->name,string);
temp->left = NULL;
temp->right = NULL;
return temp;
}
void insert(struct node *root, char* stringgg)
{
/* int flag = 5;
flag = search(root,stringgg);
if(flag == 1)
return; */
if(strcmp(stringgg,root->name) < 0)
{
if(root->left == NULL)
root->left = addNode(stringgg);
else
insert(root->left, stringgg);
}
else
{
if(root->right == NULL)
root->right = addNode(stringgg);
else
insert(root->right,stringgg);
}
}
/*int search(struct node* leaf,char* string2find)
{
if(strcmp(string2find,leaf->name) == 0)
{
leaf->count = leaf->count + 1;
return 1;
}
else if(strcmp(string2find,leaf->name) < 0)
{
return search(leaf->left,string2find);
}
else
{
return search(leaf->right,string2find);
}
return 0;
} */
void preorder(struct node *root)
{
if(root == NULL)
return;
printf("%s",root->name);
preorder(root->left);
preorder(root->right);
}
the above code prints out all the names even if there already in a tree. I was hoping that someone would be able to point out my search function errors so that it wont cause a segmentation fault when printing. Possible causes may be my inappropriate use of the return function in which i am trying to return to main if flag == 1 which means match was found so dont addnodes. but if flag does not equal 1 no match was found so go about adding nodes.
at main
while( fgets(buffer, sizeof(buffer), stdin) != NULL ){
char *p = strchr(buffer, '\n');
if(p) *p=0;//remove '\n'
at addNode
temp->count = 1;//initialize counter
return temp;
at insert
void insert(struct node *root, char* stringgg){
int cmp_stat = strcmp(stringgg,root->name);
if(cmp_stat == 0)
root->count++;
else if(cmp_stat < 0) {
if(root->left == NULL)
root->left = addNode(stringgg);
else
insert(root->left, stringgg);
} else {
if(root->right == NULL)
root->right = addNode(stringgg);
else
insert(root->right,stringgg);
}
}
at preorder
printf("%s %d\n",root->name, root->count);
The error is in searching for the very first item in the empty tree — you call
search(root, stringgg)
but root is NULL, so in search() you call
strcmp(string2find, leaf->name)
with leaf == NULL and the program crashes.
A cure: do not search BEFORE you update your tree, but rather search TO update it.
struct node* update(struct node* nd, const char* str)
{
int cmp;
// (sub)tree is empty? - create a new node with cnt==1
if(nd == NULL)
return CreateNode(str);
// test if the node found
cmp = strcmp(str, nd->name);
if(cmp == 0) // YES
nd->count ++; // update the counter
else if(cmp < 0) // NO - search in a subtree
nd->left = update(nd->left, str);
else
nd->right = update(nd->right, str);
return nd; // return the updated subtree
}
Then in main() you just update the tree and store it:
root = update(root, buffer);
Actually, the root value will change only once, on the first call, and all subsequent assignments will not change its value. However that makes the code much more readable.
I am working on a function that searches through a binary search tree in C for a name that is passed in with the function. However, I am stuck on how to format my loop so that the recusion doesn't simply end when the traversal reaches the left-most node with no children. The traversal has to be pre-order (visit myself, then my left child, then my right child).
My find function is as follows:
tnode *bst_find_by_name(tnode *ptr, const char *nom){
if(ptr != NULL){
if(strcmp(ptr->name, nom) == 0){
return ptr;
}
if(ptr->left != NULL){
return bst_find_by_name(ptr->left, nom);
}
if(ptr->right != NULL){
return bst_find_by_name(ptr->right, nom);
}
}
return NULL;
}
As you can see, currently this simply returns NULL once it reaches the left-most node that does not match the string that was passed into the function. I have to have it return NULL if it does not find a match in the tree, but at the same time I do not want it to return NULL too early before it has a chance to search every node in the tree. Any ideas?
Create a temporary variable that holds the return value. And check to see if bst_find_by_name returned something other than NULL if it returned NULL continue checking the tree.
Something like the following.
tnode *ret = NULL;
if(ptr->left != NULL){
ret = bst_find_by_name(ptr->left, nom);
}
if(ret == NULL && ptr->right != NULL){
ret = bst_find_by_name(ptr->right, nom);
}
return ret;
I prefer to write it like this:
tnode *bst_find_by_name(tnode *ptr, const char *nom) {
// accept a null node, just exit early before dereferencing it
if (ptr == NULL) {
return NULL;
}
// is it this node?
if(strcmp(ptr->name, nom) == 0){
return ptr;
}
// remember, if the first part is true, || will skip the second part
return bst_find_by_name(ptr->left, nom) || bst_find_by_name(ptr->right, nom)
}
// get the matching pointer for left or right subtree, and return
tnode *bst_find_by_name(tnode *ptr, const char *nom) {
// accept a null node, just exit early before dereferencing it
if (ptr == NULL) {
return NULL;
}
// is it this node?
if(strcmp(ptr->name, nom) == 0){
return ptr;
}
tnode * ptrtemp = bst_find_by_name(ptr->left, nom);
if(!ptrtemp) {
ptrtemp = bst_find_by_name(ptr->right, nom);
}
return ptrtemp;
}