binary search tree delete function deleting the same thing twice - c

I am trying to create a binary search tree that deletes the 2 leftmost nodes in a bst. For some reason, my code deletes the first value twice instead of moving onto the next.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct treeNode {
char *word; // the string word that is stored
int origin; // position of the word in the original text input’s line 1
struct treeNode *left; // pointer for the left children of the node
struct treeNode *right; // pointer for the right children of the node
struct treeNode *parent; // pointer for the parent of the node
};
typedef struct treeNode NODE;
NODE *
addNode(NODE * r, char *x)
{
// r = root pointer of the tree
// x = value to add into this tree
// return the root of the updated tree
NODE *p = malloc(sizeof(NODE));
p->word = malloc(strlen(x) + 1);
strcpy(p->word, x); // strcpy input: (destination, data to be copied)
// printf("%s", x);
p->parent = NULL;
p->left = NULL;
p->right = NULL;
// if tree is empty, tree consists of p only
if (r == NULL)
return p;
if (strcmp(x, r->word) > 0) {
r->right = addNode((r->right), x);
return r;
}
else {
// add new node the left subtree
r->left = addNode((r->left), x);
return r;
}
return r;
}
NODE *
getLeftMostNode(NODE * root)
{
// return the pointer to the right most node
if (root == NULL)
return NULL;
NODE *p = root;
while (p->left != NULL)
p = p->left;
return p;
}
NODE *
addTree2Tree(NODE * X, NODE * Y)
{
if (X == NULL)
return Y;
if (Y == NULL)
return X;
X = addNode(X, Y->word);
X = addTree2Tree(X, Y->left);
X = addTree2Tree(X, Y->right);
return X;
}
NODE *
removeNode(NODE * r)
{
// remove any node that store value x from tree
// r: root pointer of this tree
// return root pointer of the updated tree after removal
NODE *p = getLeftMostNode(r);
NODE *C = p->parent;
NODE *A = p->left;
NODE *B = p->right;
if (C == NULL) {
// p is root of the tree
free(p);
return addTree2Tree(A, B); // add tree A and tree B and return the new combination tree
}
if (A != NULL) {
// make A a child of C assuming position of P
if (p == C->left)
C->left = A;
else
C->right = A;
A->parent = C;
free(p);
return addTree2Tree(r, B);
}
if (B != NULL) {
if (p == C->left)
C->left = B;
else
C->right = B;
B->parent = C;
free(p);
return r;
}
if (p == C->left)
C->left = NULL;
else
C->right = NULL;
free(p); // free allocation for p
return r;
}
void
printArray(NODE * r)
{
// print all the values on the tree rooted at node "r" // print in alphabetical order
// if the tree is empty, return // print all the values on the tree rooted at node "r" // print in the in-order order: print left first, followed by root, followed by right values
if (r == NULL) {
return;
}
else {
printArray(r->left); // print all values in left subtree
printf("%s ", r->word);
printArray(r->right); // print all values in right subtree
}
}
int
main()
{
// input must be implemented by linked list, not array
NODE *root = NULL;
int ch;
char in[1000]; // input array
int len = 0;
char del[100]; // word to be deleted
char word[1000];
while ((ch = getchar()) != '\n')
in[len++] = ch;
in[len] = '\0';
// printf("%s\n", in);
int i = 0,
j = 0;
while (i <= len) {
// space to store a word
if ((in[i] == ' ') || (in[i] == '\0') || (in[i] == '\t')) {
word[j] = '\0'; // end of word
j = 0;
root = addNode(root, word);
// printf("%s\n", word);
}
else
word[j++] = in[I];
i++;
}
int k = 0;
removeNode(root);
removeNode(root);
printArray(root);
printf("\n");
return 0;
}
this is the error that I got

The function removeNode is looking for parent, but parent is never assigned in addNode. You want to assign r->right->parent = r; and r->left->parent = r;.
BST doesn't keep duplicate keys. If strcmp(x, r->word) == 0, then don't add a new node.
addNode should also be corrected so that if r is NULL, the function returns the new node immediately.
NODE* addNode(NODE* r, char* x)
{
if(!x)
return NULL;
if (!r)
{
NODE* p = malloc(sizeof(NODE)); if (!p) return NULL;
p->word = strdup(x);
p->parent = NULL;
p->left = NULL;
p->right = NULL;
return p;
}
if (strcmp(x, r->word) > 0)
{
r->right = addNode((r->right), x);
r->right->parent = r;
return r;
}
else if (strcmp(x, r->word) < 0)
{
r->left = addNode((r->left), x);
r->left->parent = r;
return r;
}
return r;
}
Modify the insert functions such that root is assigned only once:
while (i <= len)
{
if ((in[i] == ' ') || (in[i] == '\0') || (in[i] == '\t'))
{
word[j] = '\0';
j = 0;
if(!root)
root = addNode(root, word);
else
addNode(root, word);
}
else
word[j++] = in[i];
i++;
}
Double check the pointers to make sure NULL pointers are avoided. For example:
NODE* removeNode(NODE* r)
{
if(!r)
return NULL;
NODE* p = getLeftMostNode(r);
if(!p)
return NULL;
...
}
I have not checked the rest of the code but the example will work with these changes made.

Related

Binary Search Tree not sorting properly/not following my order

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):

Using recursive DFS to find node in binary tree

I have to use DFS to search a binary tree to find a node. (tok is the string I'm searching for). If it finds it, it has to return the number of nodes it traversed to find it. If it doesn't then it has to return -1.
I have tried many recursive solutions but honestly, I'm stumped. I may not be returning values correctly.
Test case:
Lets say i have a tree with the root called "John"."John" as a left child "Shayne" and a right child "Eric". Additionally, "Shayne" has a left child "Max". The output would be correct for John,Shayne and Max. But the output of Eric should be 4, since i traverse john and then shayne and then max and then Eric (considering im going left first and then right), but for Eric, im getting the output of 3
Edited with exact test case.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char* name;
char* tea;
struct node* left;
struct node* right;
};
typedef struct node Node;
int depth(struct node* root);
int dfs(struct node* root, char* tok);
int main() {
Node* John = (Node*)malloc(sizeof(Node));
John->left = NULL;
John->right = NULL;
John->name = "John";
Node* Shayne = (Node*)malloc(sizeof(Node));
Shayne->left = NULL;
Shayne->right = NULL;
Shayne->name = "Shayne";
Node* Eric = (Node*)malloc(sizeof(Node));
Eric->left = NULL;
Eric->right = NULL;
Eric->name = "Eric";
Node* Max = (Node*)malloc(sizeof(Node));
Max->left = NULL;
Max->right = NULL;
Max->name = "Max";
John->left = Shayne;
Shayne->left = Max;
John->right = Eric;
printf("%d",dfs(John,"Eric"));
}
int depth(struct node* root) {
if (root == NULL) {
return 0;
}
int l = depth(root->left);
int r = depth(root->right);
int d = max(l, r) + 1;
return d;
}
int dfs(struct node* root, char* tok) {
if (root == NULL) {
return 0;
}
if (strcmp(root->name, tok) == 0) {
return 1;
}
else {
int l = dfs(root->left, tok);
if (l != -1) {
return 1 + l;
}
int r = dfs(root->right, tok);
if (r != -1) {
return 1+l+ r;
}
return -1;
}
}
You correctly add 1 to the return value when the value has been found in an immediate child to produce the number of nodes. But it also means that you will return 2 to your parent.
You have to change your test to
if (l != -1) { //found on left child
return 1 + l;
}
The only problem with your function is that when you are returning from the child node you are always checking the value of l with 1 for instance:
int l = dfs(root->left, tok);
if (l == 1) { //found on left child
return 1 + l;
}
which will work fine for the first 2 nodes but then the value of the return becomes 2,3,4,.... in that case it will skip the if and return -1 again, so to solving this problem a good approach will be to check if the return value is not -1, for example:
int l = dfs(root->left, string);
if (l != -1) {
return 1 + l;
}
int r = dfs(root->right, string);
if (r != -1) {
return 1 + r;
}
Hope this gives you the answer.

Insertion into AVL tree only replaces root node

I'm currently working on an assignment where the N most frequent words in a book (.txt) must be printed. The issue that I'm currently facing is that when I add a node to one of my trees, it simply replaces the root node and thus, the tree remains as a single node.
Code snippet which adds words from the file "stopwords.txt" to a tree named stopwords:
Dict stopwords = newDict();
if (!readFile("stopwords.txt"))
{
fprintf(stderr, "Can't open stopwords\n");
exit(EXIT_FAILURE);
}
FILE *fp = fopen("stopwords.txt", "r");
while (fgets(buf, MAXLINE, fp) != NULL)
{
token = strtok(buf, "\n");
DictInsert(stopwords, buf); //the root is replaced here
}
fclose(fp);
The data structures are defined as follows:
typedef struct _DictNode *Link;
typedef struct _DictNode
{
WFreq data;
Link left;
Link right;
int height;
} DictNode;
typedef struct _DictRep *Dict;
struct _DictRep
{
Link root;
};
typedef struct _WFreq {
char *word; // word buffer (dynamically allocated)
int freq; // count of number of occurences
} WFreq;
Code to insert and rebalance tree:
// create new empty Dictionary
Dict newDict(void)
{
Dict d = malloc(sizeof(*d));
if (d == NULL)
{
fprintf(stderr, "Insufficient memory!\n");
exit(EXIT_FAILURE);
}
d->root = NULL;
return d;
}
// insert new word into Dictionary
// return pointer to the (word,freq) pair for that word
WFreq *DictInsert(Dict d, char *w)
{
d->root = doInsert(d->root, w); //the root is replaced here before doInsert runs
return DictFind(d, w);
}
static int depth(Link n)
{
if (n == NULL)
return 0;
int ldepth = depth(n->left);
int rdepth = depth(n->right);
return 1 + ((ldepth > rdepth) ? ldepth : rdepth);
}
static Link doInsert(Link n, char *w)
{
if (n == NULL)
{
return newNode(w);
}
// insert recursively
int cmp = strcmp(w, n->data.word);
if (cmp < 0)
{
n->left = doInsert(n->left, w);
}
else if (cmp > 0)
{
n->right = doInsert(n->right, w);
}
else
{ // (cmp == 0)
// if time is already in the tree,
// we can return straight away
return n;
}
// insertion done
// correct the height of the current subtree
n->height = 1 + max(height(n->left), height(n->right));
// rebalance the tree
int dL = depth(n->left);
int dR = depth(n->right);
if ((dL - dR) > 1)
{
dL = depth(n->left->left);
dR = depth(n->left->right);
if ((dL - dR) > 0)
{
n = rotateRight(n);
}
else
{
n->left = rotateLeft(n->left);
n = rotateRight(n);
}
}
else if ((dR - dL) > 1)
{
dL = depth(n->right->left);
dR = depth(n->right->right);
if ((dR - dL) > 0)
{
n = rotateLeft(n);
}
else
{
n->right = rotateRight(n->right);
n = rotateLeft(n);
}
}
return n;
}
static Link newNode(char *w)
{
Link n = malloc(sizeof(*n));
if (n == NULL)
{
fprintf(stderr, "Insufficient memory!\n");
exit(EXIT_FAILURE);
}
n->data.word = w;
n->data.freq = 1;
n->height = 1;
n->left = NULL;
n->right = NULL;
return n;
}
// Rotates the given subtree left and returns the root of the updated
// subtree.
static Link rotateLeft(Link n)
{
if (n == NULL)
return n;
if (n->right == NULL)
return n;
Link rightNode = n->right;
n->right = rightNode->left;
rightNode->left = n;
n->height = max(height(n->left), height(n->right)) + 1;
rightNode->height = max(height(rightNode->right), n->height) + 1;
return rightNode;
}
// Rotates the given subtree right and returns the root of the updated
// subtree.
static Link rotateRight(Link n)
{
if (n == NULL)
return n;
if (n->left == NULL)
return n;
Link leftNode = n->left;
n->left = leftNode->right;
leftNode->right = n;
n->height = max(height(n->left), height(n->right)) + 1;
leftNode->height = max(height(leftNode->right), n->height) + 1;
return leftNode;
}
I believe that most of the code is functional and it is simply the insertion which fails. When I attempted to debug this with gdb, I had discovered that the root node (d->root) was replaced before the recursive insert function (doInsert) was run, causing the program to always return the node n which, as a result, already exists in the tree. For example, if the text file contained the following:
a
b
c
then the program would first insert "a" as stopwords->root, then "b" would replace "a" and become the new stopwords->root, finally "c" would replace "b" as the stopwords->root, resulting in a tree with one node, "c".
There are many inconsistencies in your code.
One mistake is here:
d->root = doInsert(d->root, w);
You reassign unconditionally the root each time when you insert a new node.
You are supposed to return the new node from the function doInsert and to reassign the root only if the new node had become a new root.
But other mistake that you make is that you return from doInsert a local variable n that was not newly allocated but that was initialized to point to the previous root.
Inside doInsert you need to allocate a new node NEW and use a variable x to walk down from the root until you find a place to insert a new allocated node NEW. If x stops at root then you reinitialize the d->root = NEW.
Your function newNode just stores the passed string pointer, so what is pointed at will change when you modify the original string.
To prevent that, you should copy the input string on node insertions.
To archive that,
n->data.word = w;
should be
n->data.word = malloc(strlen(w) + 1);
if (n->data.word == NULL)
{
fprintf(stderr, "Insufficient memory!\n");
exit(EXIT_FAILURE);
}
strcpy(n->data.word, w);
Add #include <string.h> to use strlen() and strcpy() if it isn't.

Error allocating memory for temp in queue push in c invalid write size of 8 from valgrind

This is my push function
void push(struct Map *map, struct Location location){
struct Node *temp = map->front;
temp->loc = location; //this line causes the error
temp->next = NULL;
if(map->rear == NULL) { // if queue empty
map->front = temp; // First NODE
map->rear = map->front;
}else{// if there is stuff in the queue
map->rear->next = temp;
map->rear = temp;
// Insert End
}
free(temp);
}
and I am getting this error
==2301== Invalid write of size 8
==2301== at 0x401148: push (3146.c:239)
==2301== by 0x400DE7: findEntrance (3146.c:164)
==2301== by 0x400820: main (3146.c:55)
==2301== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==2301==
I am doing a breadth first search on a grid of characters arranged to be a maze. I have been having trouble getting no memory leaks so I have finally found that using malloc helps, but I don't understand why I cannot do this data assignment without a segfault
The alternative is to not free it and have memory leaks, which I don't think is an acceptable solution. Where is my logic wrong?
Below this is the whole program
#include <stdio.h>
#include <stdlib.h>
struct Location;
struct Map;
struct Node;
//function names seem to self describe
void pathFinder(struct Map*);
void findEntrance(struct Map*);
void readInMap(struct Map*);
void printMap(struct Map*);//to screen
/* Q funcs */
void pop(struct Map*);
void push(struct Map*, struct Location);
struct Location {// simple location type
int x;
int y;
};
struct Node {//standard linked list node
struct Location loc;
struct Node *next;
};
struct Map { //variable size encompassing array, and dimension variables
char arr[100][100];
int xLength;//dimensions
int yLength;
int complete;
struct Node *rear;//Q pointers
struct Node *front;
struct Node *currLoc; //temp for BFS
struct Location entrance;
};
int main(){
struct Map map;//the one map to rule them all
map.xLength = 0;//map dimensions
map.yLength = 0;
map.front = NULL; // queue pointers init
map.rear = NULL;
map.currLoc = NULL;
map.entrance.x = 0;
map.entrance.y = 0;
map.complete = 0;
readInMap(&map);
findEntrance(&map);//start off by finding where to start
pathFinder(&map); // problem solver method
printMap(&map);
free(map.front);
free(map.rear);
free(map.currLoc);
return 0;
}
void pathFinder(struct Map *map){
int x;//should be the entrance already pushed from findEntrance
int y;
int done = 0;
struct Location temp;
temp.x = 0;// temp for pushing locations that are adjacent 0's
temp.y = 0;
while(map->front != NULL){
map->currLoc = map->front;//currLoc is just a copy so that we can pop the map location of currLoc from Q
pop(map);// pop so it cant be used twice in this loop
x = map->currLoc->loc.x;
y = map->currLoc->loc.y;
temp.x = 0;
temp.y = 0;
if(map->arr[y][x] == '0'){//protection of 1 values from replacement
map->arr[y][x] = 'X';//replace the array position loc w x
}
if(map->arr[y][x] == '0'){//protection of 1 values from replacement
map->arr[y][x] = 'X';//replace the array position loc w x
printf("test\n");
}
/* find adjacent 0's */
if((y < map->xLength)&&(map->arr[y+1][x] == '0')){
temp.x = x;
temp.y = y+1;
push(map, temp);
}
if((x < map->xLength)&&(map->arr[y][x+1] == '0')){
temp.x = x+1;
temp.y = y;
push(map, temp);
}
if((y > 0)&&(map->arr[y-1][x] == '0')){
temp.x = x;
temp.y = y-1;
push(map, temp);
}
if((x > 0)&&(map->arr[y][x-1] == '0')){
temp.x = x-1;
temp.y = y;
push(map, temp);
}
if((x == 0)||(x == map->xLength)||(y == 0)||(y == map->yLength)){ //then its not on the edge
if((x != map->entrance.x)&&(y != map->entrance.y)){
map->front = NULL;
map->complete++;
}
}
}
}
void findEntrance(struct Map *map){
struct Location entrance;
int done = 0;
int y=0;//index of current row depth
int x=0;//index of current column depth
if (done == 0){
for (x=0;x<=map->xLength;x++){ // top row
if (map->arr[y][x] == '0') {
entrance.x = x;
entrance.y = y;
done = 1;
}
}
}
if (done == 0){
for(y=0;y<=map->yLength;y++){//down the right side
if (map->arr[y][map->xLength] == '0') {
entrance.x = x;
entrance.y = y;
done = 1;
}
}
}
if (done == 0){
for(x;x>=0;x--){//bottom row RtoL
if (map->arr[map->yLength][x] == '0') {
entrance.x = x;
entrance.y = y;
done = 1;
}
}
}
if (done == 0){
for(y;y>=0;y--){//up the left side
if (map->arr[y][0] == '0') {
entrance.x = x;
entrance.y = y;
done = 1;
}
}
}
map->entrance = entrance;
push(map, map->entrance);
}
void readInMap(struct Map *map){
FILE *fptr;
char c;
char file_name[20];
int i,j;
int rows;
int cols;
int x,y;
printf("Size\n");
printf("Rows:");
scanf("%i", &rows);
printf("Columns:");
scanf("%i", &cols);
map->xLength = cols-1; //[y][xLength]
map->yLength = rows-1; //[yLength][x]
for (x=0;x<100;x++){
for (y=0;y<100;y++){
map->arr[x][y] = '1';//whole array is 1
}
}
printf("Type in the name of the file containing the Field\n");
scanf("%s",file_name);
fptr=fopen(file_name, "r");
for (i = 0; i <= map->xLength; i++){
for (j = 0; j <= map->yLength; j++){
c=fgetc(fptr); //handles new line character and spaces
while ( !((c == '1') || (c =='0')) ) {
c=fgetc(fptr);
}
map->arr[i][j] = c;
}
}
printf("\n");
fclose(fptr);
}
void printMap(struct Map *map){
int y;//index of current row depth
int x;//index of current column depth
for (x=0;x<=map->xLength;x++){
for (y=0;y<=map->yLength;y++){//current pos (x,y)
printf("%c", map->arr[x][y]);
}
printf("\n");
}
if(map->complete != 0){
printf("\n An exit to the maze was found that is not the entrance\n");
}else{
printf("\n No exit was found \n");
}
}
void pop(struct Map *map){
if (map->front != NULL){//if not empty
if (map->front == map->rear){
map->rear = NULL;//if the line length is 1, empty it
map->front = NULL;
}else{
map->front = map->front->next;//next in line
}
}else{
map->rear = NULL;//empty out the queue
map->front = NULL;
}
}
void push(struct Map *map, struct Location location){
struct Node *temp = (struct Node*)malloc(sizeof(struct Node));
temp->loc = location;
temp->next = NULL;
if(map->rear == NULL) { // if queue empty
map->front = temp; // First NODE
map->rear = map->front;
}else{// if there is stuff in the queue
map->rear->next = temp;
map->rear = temp;
// Insert End
}
free(temp);
}
When the Map is empty, both front and rear are NULL. So temp->loc is dereferencing a NULL pointer.
You need to malloc the new node and add that to the list. Additionally, you don't want to free here, as that deallocates the memory that you just added to the list.
void push(struct Map *map, struct Location location){
struct Node *temp = malloc(sizeof(struct Node));
temp->loc = location;
temp->next = NULL;
if(map->rear == NULL) { // if queue empty
map->front = temp; // First NODE
map->rear = map->front;
}else{// if there is stuff in the queue
map->rear->next = temp;
map->rear = temp;
// Insert End
}
}
In pop is where you want to deallocate the memory:
void pop(struct Map *map){
struct Node *temp = map->front;
if (map->front != NULL){//if not empty
if (map->front == map->rear){
map->rear = NULL;//if the line length is 1, empty it
map->front = NULL;
}else{
map->front = map->front->next;//next in line
}
free(temp);
}else{
map->rear = NULL;//empty out the queue
map->front = NULL;
}
}

realloc in recursion in trees

I am trying to find the maximum sum leaf to root path in a Binary Tree as in below
http://www.geeksforgeeks.org/find-the-maximum-sum-path-in-a-binary-tree/
1) I am unable to find why the path doesn't get printed in the main()
Is this because of wrong reallocs in the function.?
2) Also is my free correct?
#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
/* A tree node structure */
struct node
{
int data;
struct node *left;
struct node *right;
};
// Returns the maximum sum and prints the nodes on max sum path
int maxsumtoleaf(struct node *node,int** path,int &height)
{
// base case
if (node == NULL)
return 0;
printf("\n At node %d,",node->data);
if (node->left==NULL && node->left==NULL) {
*path=(int*)realloc(*path,sizeof(int));
*path[0]=node->data;
height=1;
printf("\n value is %d,",*path[0]);
return node->data;
}
// find the target leaf and maximum sum
int rightheight=0,leftheight=0;
int *path1=NULL,*path2=NULL;
int left=maxsumtoleaf (node->left,&path1,leftheight);
int right=maxsumtoleaf (node->right,&path2,rightheight);
if ( left > right ) {
printf("\nbefore left is");
for(int i=0;i<leftheight;i++)
printf("%d,",path1[i]);
path1=(int*)realloc(path1,sizeof(int)*(leftheight+1));
if ( path1 == NULL ) {
printf("Out of Memory!\n");
return 0;
}
path1[leftheight]=node->data;
height=leftheight+1;
printf("\nafter left %d is ",leftheight);
for(int i=0;i<height;i++)
printf("%d,",path1[i]);
path=&path1;
return left+node->data;
} else {
printf("\nbefore right is");
for(int i=0;i<rightheight;i++)
printf("%d,",path2[i]);
path2=(int*)realloc(path2,sizeof(int)*(rightheight+1));
if ( path2 == NULL ) {
printf("Out of Memory!\n");
return 0;
}
path2[rightheight]=node->data;
height=rightheight+1;
printf("\nafter right is");
for(int i=0;i<height;i++)
printf("%d,",path2[i]);
path=&path2;
return right+node->data;
}
// return maximum sum
}
/* Utility function to create a new Binary Tree node */
struct node* newNode (int data)
{
struct node *temp = new struct node;
temp->data = data;
temp->left = NULL;
temp->right = NULL;
return temp;
}
/* Driver function to test above functions */
int main()
{
struct node *root = NULL;
/* Constructing tree given in the above figure */
/* (8<--2->-4)<-10->7 */
root = newNode(10);
root->left = newNode(-2);
root->right = newNode(7);
root->left->left = newNode(8);
root->left->right = newNode(-4);
int sum=0;
int** path=NULL;
int height=0;
sum = maxsumtoleaf(root,path,height);
printf ("\nSum of the nodes is %d ,len=%d", sum,height);
printf ("\nPath is ");
for(int i=0;i<height;i++)
printf("%d,",*path[i]);
free(path);
getchar();
return 0;
}
Output:
At node 10,
At node -2,
At node 8,
value is 8,
At node -4,
value is -4,
before left is8,
after left 1 is 8,-2,
At node 7,
value is 7,
before right is7,
after right is7,10,
Sum of the nodes is 17 ,len=2
Path is ---> Breaks at this point in main()
Code is C++ with passing args by reference and using new.
To make C, lots of little fixes including how C "reference" variable are passed (explicitly by address).
You are not doing rellloc() correctly should the allocation fail as you have lost the original pointer.
Always good form to NULL a pointer after freeing it.
#include <stdio.h>
#include <string.h>
#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
/* A tree node structure */
struct node {
int data;
struct node *left;
struct node *right;
};
// Returns the maximum sum and prints the nodes on max sum path
int maxsumtoleaf(struct node *node, int** path, int *height) {
// base case
if (node == NULL)
return 0;
printf("\n At node %d,", node->data);
if (node->left == NULL && node->left == NULL) {
*path = (int*) realloc(*path, sizeof(int));
(*path)[0] = node->data;
*height = 1;
printf("\n value is %d,", *path[0]);
return node->data;
}
// find the target leaf and maximum sum
int rightheight = 0, leftheight = 0;
int *path1 = NULL, *path2 = NULL;
int left = maxsumtoleaf(node->left, &path1, &leftheight);
int right = maxsumtoleaf(node->right, &path2, &rightheight);
if (left > right) {
printf("\nbefore left is");
for (int i = 0; i < leftheight; i++)
printf("%d,", path1[i]);
path1 = (int*) realloc(path1, sizeof(int) * (leftheight + 1));
if (path1 == NULL) {
printf("Out of Memory!\n");
return 0;
}
path1[leftheight] = node->data;
*height = leftheight + 1;
printf("\nafter left %d is ", leftheight);
for (int i = 0; i < *height; i++)
printf("%d,", path1[i]);
*path = path1;
return left + node->data;
} else {
printf("\nbefore right is");
for (int i = 0; i < rightheight; i++)
printf("%d,", path2[i]);
path2 = (int*) realloc(path2, sizeof(int) * (rightheight + 1));
if (path2 == NULL) {
printf("Out of Memory!\n");
return 0;
}
path2[rightheight] = node->data;
*height = rightheight + 1;
printf("\nafter right is");
for (int i = 0; i < *height; i++)
printf("%d,", path2[i]);
*path = path2;
return right + node->data;
}
// return maximum sum
}
/* Utility function to create a new Binary Tree node */
struct node* newNode(int data) {
struct node *temp = malloc(sizeof *temp); // new struct node;
temp->data = data;
temp->left = NULL;
temp->right = NULL;
return temp;
}
/* Driver function to test above functions */
int main() {
struct node *root = NULL;
/* Constructing tree given in the above figure */
/* (8<--2->-4)<-10->7 */
root = newNode(10);
root->left = newNode(-2);
root->right = newNode(7);
root->left->left = newNode(8);
root->left->right = newNode(-4);
int sum = 0;
int* path = NULL;
int height = 0;
sum = maxsumtoleaf(root, &path, &height);
printf("\nSum of the nodes is %d ,len=%d", sum, height);
printf("\nPath is %p ", path);
// return 0;
for (int i = 0; i < height; i++)
printf("%d,", path[i]);
free(path);
path = NULL;
// getchar();
return 0;
}
Preferred realoc() use
// Somehow these are to be updated (initial to NULL and 0)
some_type *current_ptr;
size_t current_element_count; // best too use type size_t
size_t new_element_count = some_function(current_size);
void *new_ptr = realloc(current_ptr, new_element_count * sizeof *current_ptr);
if (new_ptr == NULL && new_element_count > 0) {
Handle_OOM(); // current_ptr is still same & current_element_count elements
return;
}
current_ptr = new_ptr;
current_element_count = new_element_count;
// continue on the happy path

Resources