Related
I am trying to encode an AVL binary tree in the C language. My implementation uses an over-arching struct to keep track of the length of the binary tree (i.e. number of nodes), as well as a pointer t the root, and the init status of the data structure. I have been able to encode an implementation correctly balances the tree at every insertion. However, I am having problems balancing the tree when I delete a node. I am trying to use an example listed on GeeksforGeeks (https://www.geeksforgeeks.org/deletion-in-an-avl-tree/) and I am consistently getting an incorrect answer. The problem must be in the delete_int8_node function, but i cannot see where. Unfortunately the example is lengthy, as several functions are required to provide a working example. Any help would be appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdbool.h>
typedef struct int8_btree {
int8_t key;
struct int8_btree *left;
struct int8_btree *right;
int height;
} int8_btree;
typedef struct {
size_t active_length;
struct int8_btree *root;
bool status;
} Int8BT
void init_int8_btree(Int8BT *tree) {
tree->active_length = 0;
tree->root = NULL;
tree->status = true;
}
// ================================================================================
// ================================================================================
// NEW_TYPE_NODE (PRIVATE FUNCTIONS)
int8_btree *new_int8_node(int8_t key) {
struct int8_btree *node = malloc(sizeof(int8_btree));
if (node == NULL) return node;
node->key = key;
node->left = NULL;
node->right = NULL;
node->height = 1;
return node;
}
// ================================================================================
// ================================================================================
// TYPE_NODE_HEIGHT FUNCTIONS (PRIVAT FUNCTIONS)
int int8_node_height(int8_btree *node) {
if (node == NULL) return 0;
return node->height;
}
// ================================================================================
// ================================================================================
// MAX_TYPE_NUM FUNCTION (PRIVATE FUNCTIONS)
int max_num(int a, int b) {
return (a > b)? a : b;
}
// ================================================================================
// ================================================================================
// RIGHT_TYPE_ROTATE FUNCTIONS (PRIVATE FUNCTIONS)
int8_btree *right_int8_rotate(int8_btree * y) {
struct int8_btree *x = y->left;
struct int8_btree *T2 = x->right;
// Perform rotation
x->right = y;
y->left = T2;
x->height = max_num(int8_node_height(y->left), int8_node_height(y->right)) + 1;
y->height = max_num(int8_node_height(x->left), int8_node_height(x->right)) + 1;
return x;
}
// ================================================================================
// ================================================================================
// LEFT_STRING_ROTATE FUNCTIONS (PRIVATE FUNCTIONS)
int8_btree *left_int8_rotate(int8_btree *x) {
struct int8_btree *y = x->right;
struct int8_btree *T2 = y->left;
// Perform rotation
y->left = x;
x->right = T2;
x->height = max_num(int8_node_height(x->left), int8_node_height(x->right)) + 1;
y->height = max_num(int8_node_height(y->left), int8_node_height(y->right)) + 1;
return y;
}
// ================================================================================
// ================================================================================
// TYPE_NODE_BALANCE FUNCTION (PRIVATE FUNCTIONS)
int int8_node_balance(int8_btree *node) {
if (node == NULL) return 0;
return int8_node_height(node->left) - int8_node_height(node->right);
}
// ================================================================================
// ================================================================================
// PUSH_TYPE_BTREE FUNCTION (PRIVATE FUNCTIONS)
int8_btree *insert_int8_btree(int8_btree *node, int8_t key) {
/* 1. Perform the normal BST insertion */
if (node == NULL)
return new_int8_node(key);
if (key < node->key)
node->left = insert_int8_btree(node->left, key);
else if (key > node->key)
node->right = insert_int8_btree(node->right, key);
else // Equal keys are not allowed in BST
return node;
/* 2. Update height of this ancestor node */
node->height = 1 + max_num(int8_node_height(node->left),
int8_node_height(node->right));
/* 3. Get the balance factor of this ancestor
node to check whether this node became
unbalanced */
short int balance = int8_node_balance(node);
// If this node becomes unbalanced, then
// there are 4 cases
// Left Left Case
if (balance > 1 && key < node->left->key)
return right_int8_rotate(node);
// Right Right Case
if (balance < -1 && key > node->right->key)
return left_int8_rotate(node);
// Left Right Case
if (balance > 1 && key > node->left->key)
{
node->left = left_int8_rotate(node->left);
return right_int8_rotate(node);
}
// Right Left Case
if (balance < -1 && key < node->right->key)
{
node->right = right_int8_rotate(node->right);
return left_int8_rotate(node);
}
/* return the (unchanged) node pointer */
return node;
}
// ================================================================================
// ================================================================================
// PUSH_TYPE_BTREE FUNCTIONS
int push_int8_btree(Int8BT *btree, int8_t key) {
if (btree->status != true) {
fprintf(stderr, "Binary tree struct not initializex\n");
return -1;
}
btree->root = insert_int8_btree(btree->root, key);
if (btree->root == NULL) {
fprintf(stderr, "Malloc failed in file %s on line %d\n", __FILE__, __LINE__);
return -1;
}
btree->active_length += 1;
return 1;
}
// ================================================================================
// ================================================================================
// FREETYPE_FUNCTIONS (PRIVATE FUNCTIONS)
void freeint8(int8_btree *root) {
if (root == NULL) return;
freeint8(root->right);
freeint8(root->left);
free(root);
}
// ================================================================================
// ================================================================================
// FREE_TYPE_BTREE FUNCTIONS
void free_int8_btree(Int8BT *btree) {
if (btree->status != true) {
fprintf(stderr, "Unitialized binary tree struct cannot be freed\n");
return;
}
freeint8(btree->root);
}
// ================================================================================
// ================================================================================
// MIN_TYPE_NODE (PRIVATE FUNCTIONS)
int8_btree *min_int8_node(int8_btree *root) {
struct int8_btree *current = root;
while (current->left != NULL) {
current = current->left;
}
return current;
}
// ================================================================================
// ================================================================================
// DELETE_TYPE_NODE (PRIVATE FUNCTIONS)
int8_btree *delete_int8_node(int8_btree *root, int8_t key) {
// STEP 1: PERFORM STANDARD BST DELETE
if (root == NULL)
return root;
// If the key to be deleted is smaller than the
// root's key, then it lies in left subtree
if ( key < root->key )
root->left = delete_int8_node(root->left, key);
// If the key to be deleted is greater than the
// root's key, then it lies in right subtree
else if( key > root->key )
root->right = delete_int8_node(root->right, key);
// if key is same as root's key, then This is
// the node to be deleted
else
{
// node with only one child or no child
if( (root->left == NULL) || (root->right == NULL) )
{
struct int8_btree *temp = root->left ? root->left :
root->right;
// No child case
if (temp == NULL)
{
temp = root;
root = NULL;
}
else // One child case
*root = *temp; // Copy the contents of
// the non-empty child
free(temp);
}
else
{
// node with two children: Get the inorder
// successor (smallest in the right subtree)
struct int8_btree* temp = min_int8_node(root->right);
// Copy the inorder successor's data to this node
root->key = temp->key;
// Delete the inorder successor
root->right = delete_int8_node(root->right, temp->key);
}
}
// If the tree had only one node then return
if (root == NULL)
return root;
// STEP 2: UPDATE HEIGHT OF THE CURRENT NODE
root->height = 1 + max_num(int8_node_height(root->left),
int8_node_height(root->right));
// STEP 3: GET THE BALANCE FACTOR OF THIS NODE (to
// check whether this node became unbalanced)
short int balance = int8_node_balance(root);
// If this node becomes unbalanced, then there are 4 cases
// Left Left Case
if (balance > 1 && int8_node_balance(root->left) >= 0)
return right_int8_rotate(root);
// Left Right Case
if (balance > 1 && int8_node_balance(root->left) < 0)
{
root->left = left_int8_rotate(root->left);
return right_int8_rotate(root);
}
// Right Right Case
if (balance < -1 && int8_node_balance(root->right) <= 0)
return left_int8_rotate(root);
// Right Left Case
if (balance < -1 && int8_node_balance(root->right) > 0)
{
root->right = right_int8_rotate(root->right);
return left_int8_rotate(root);
}
return root;
}
// ================================================================================
// ================================================================================
// POP_TYPE_BTREE FUNCTIONS
void pop_int8_btree(Int8BT *btree, int8_t key) {
btree->root = delete_int8_node(btree->root, key);
btree->active_length -= 1;
//if (btree->status != true) {
// fprintf(stderr, "Cannon pop binary tree struct that is not initialized\n");
// return;
//}
//struct int8_btree *current = btree->root;
//btree->root = delete_int8_node(btree->root, key);
//if (btree->root == current && btree->root != NULL) btree->active_length -= 1;
}
void print_preorder(int8_btree *root)
{
if(root != NULL)
{
printf("%d ", root->key);
print_preorder(root->left);
print_preorder(root->right);
}
}
// --------------------------------------------------------------------------------
void print_int8_tree(Int8BT *tree) {
print_preorder(tree->root);
printf("\n");
}
// --------------------------------------------------------------------------------
void test_repeat_int8_list(void **state) {
Int8BT tree;
init_int8_btree(&tree);
push_int8_btree(&tree, 9);
push_int8_btree(&tree, 5);
push_int8_btree(&tree, 10);
push_int8_btree(&tree, 0);
push_int8_btree(&tree, 6);
push_int8_btree(&tree, 11);
push_int8_btree(&tree, -1);
push_int8_btree(&tree, 1);
push_int8_btree(&tree, 2);
print_int8_tree(&tree);
// Correctly prints 9 1 0 -1 5 2 6 10 11
pop_int8_btree(&tree, 10);
print_int8_tree(&tree);
// Incorrectly prints 9 1 0 -1 5 2 6 11
// Should print 1 0 -1 9 5 2 6 11
free_int8_btree(&tree);
}
The problem is not in the deletion directly. It is the depth caculation in the rotate right function and thus also affects the insertion.
There you flipped the x and y depth assignment, A corrected version is:
int8_btree *right_int8_rotate(int8_btree * y) {
struct int8_btree *x = y->left;
struct int8_btree *T2 = x->right;
// Perform rotation
x->right = y;
y->left = T2;
// before it was x->height
y->height = max_num(int8_node_height(y->left), int8_node_height(y->right)) + 1;
// before it was y->height
x->height = max_num(int8_node_height(x->left), int8_node_height(x->right)) + 1;
return x;
}
in general it would be helpful to print the tree including the depth information, so you could see unplausible tree already after creation.
Especially with trees, I recommend Graphviz.
#include <assert.h>
static void subgraph(const struct int8_btree *const node, FILE *const fp) {
assert(node && fp);
fprintf(fp, "\t\tnode%p [label=\"%d:%d\"];\n",
(const void *)node, node->height, (int)node->key);
if(node->left) fprintf(fp, "\t\tnode%p -> node%p [arrowhead=rnormal];\n",
(const void *)node, (const void *)node->left);
if(node->right) fprintf(fp, "\t\tnode%p -> node%p [arrowhead=lnormal];\n",
(const void *)node, (const void *)node->right);
if(node->left) subgraph(node->left, fp);
if(node->right) subgraph(node->right, fp);
}
static void graph(const Int8BT *const tree, const char *const fn) {
FILE *fp;
assert(tree && fn);
if(!(fp = fopen(fn, "w"))) { perror(fn); return; }
fprintf(fp, "digraph {\n"
"\tgraph [truecolor=true, bgcolor=transparent, fontname=modern];\n"
"\tnode [shape=circle, fontname=modern, "
"style=filled, fillcolor=Grey95];\n");
if(!tree->root) fprintf(fp, "empty\n");
else subgraph(tree->root, fp);
fprintf(fp, "\tnode [colour=red];\n"
"}\n");
fclose(fp);
}
Then you can,
graph(&tree, "tree01.gv");
Immediately, you can tell that the heights don't sense.
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):
I'm working on a program that calculates any number in the Fibonacci Sequence without using the int data type since it would overflow. Instead I am using linked lists to hold the digits that represent each number. My current issue is with freeing memory allocated to linked lists that I no longer need. If I'm calculating F(10000), I'd like the thousands of previous lists to be freed. The program as is produces each value up to "F(7) = 13" before crashing and showing "exit status -1". I'd really just like to know what's causing this error and go from there. Any help is appreciated. Thank you and I apologize for the large amount of code.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
int digit;
struct Node *next;
} Node;
typedef struct ListyInt
{
Node *head;
int length;
} ListyInt;
Node *create_node(unsigned int digit, ListyInt *listy);
Node *removeNode(Node *node, ListyInt *listy);
void listyPrintHelper(Node *current);
ListyInt *destroyListyInt(ListyInt *listy);
ListyInt *fib(unsigned int n);
void listyPrint(ListyInt *p)
{
if (p == NULL || p->head == NULL)
{
printf("(null pointer)\n");
return;
}
listyPrintHelper(p->head);
printf("\n");
}
void listyPrintHelper(Node *current)
{
if (current == NULL)
return;
listyPrintHelper(current->next);
printf("%d", current->digit);
}
int main()
{
int i;
ListyInt *p;
for (i = 0; i <= 1000; i++)
{
printf("F(%d) = ", i);
listyPrint(p = fib(i));
destroyListyInt(p);
}
return 0;
}
ListyInt *listyAdd(ListyInt *p, ListyInt *q)
{
ListyInt *listy = NULL;
Node *ptemp = NULL;
Node *qtemp = NULL;
Node *temp = NULL;
ListyInt *temp_list = NULL;
unsigned int x = 0;
unsigned int count = 0;
if (p == NULL || q == NULL)
{
return NULL;
}
listy = malloc(sizeof(ListyInt));
if (listy == NULL)
{
return NULL;
}
listy->length = 0;
if (q->length > p->length)
{
temp_list = q;
q = p;
p = temp_list;
}
while (count < p->length)
{
if (count == 0)
{
x = p->head->digit + q->head->digit;
ptemp = p->head->next;
qtemp = q->head->next;
listy->head = create_node(x, listy);
temp = listy->head;
temp->next = create_node(0, listy);
if (temp->digit > 9)
{
temp->digit = temp->digit - 10;
temp->next->digit = temp->next->digit + 1;
}
}
else
{
temp->next->next = create_node(0, listy);
if (qtemp == NULL)
{
temp->next->digit += ptemp->digit;
ptemp = ptemp->next;
temp = temp->next;
}
else
{
x = ptemp->digit + qtemp->digit;
temp->next->digit += x;
if (temp->next->digit > 9)
{
temp->next->digit = temp->next->digit - 10;
temp->next->next->digit = temp->next->next->digit + 1;
}
qtemp = qtemp->next;
ptemp = ptemp->next;
temp = temp->next;
}
}
if (count == p->length - 1 && temp->next->digit == 0)
{
temp->next = removeNode(temp->next, listy);
}
count++;
}
return listy;
}
ListyInt *destroyListyInt(ListyInt *listy)
{
if (listy == NULL)
{
return NULL;
}
Node *current = listy->head;
Node *temp;
while (current != NULL)
{
temp = current->next;
free(current);
current = temp;
}
free(listy);
return NULL;
}
ListyInt *fib(unsigned int n)
{
ListyInt *spiral = malloc(sizeof(ListyInt));
ListyInt *p = NULL;
ListyInt *q = NULL;
unsigned int count = 2;
if (spiral == NULL)
{
return NULL;
}
if (n == 0)
{
spiral->head = create_node(0, spiral);
return spiral;
}
if (n == 1)
{
spiral->head = create_node(1, spiral);
return spiral;
}
p = malloc(sizeof(ListyInt));
p->head = create_node(0, p);
q = malloc(sizeof(ListyInt));
q->head = create_node(1, q);
while (count <= n)
{
spiral = listyAdd(p, q);
destroyListyInt(p);
p = q;
q = spiral;
count++;
}
return spiral;
}
Node *create_node(unsigned int digit, ListyInt *listy)
{
if (listy == NULL)
{
return NULL;
}
Node *new_node = malloc(sizeof(Node));
new_node->digit = digit;
new_node->next = NULL;
listy->length++;
return new_node;
}
Node *removeNode(Node *node, ListyInt *listy)
{
if (node == NULL)
{
return NULL;
}
if (listy == NULL)
{
return NULL;
}
free(node);
node = NULL;
listy->length--;
return NULL;
}
I'd really just like to know what's causing this error and go from there.
Long story short, C's equivalent of a NullPointerException, as far as I can tell.
Long story longer, I haven't had time to fully examine your code or debug it, but I have had time to run it through gdb, which is included with most Linux installations. If you're using Visual Studio, I vaguely remember there being a debug mode, which should show you roughly the same information, just in a different place. This is GDB's output:
Starting program: /home/ubuntu/C/a.out
F(0) = 0
F(1) = 1
F(2) = 1
F(3) = 2
F(4) = 3
F(5) = 5
F(6) = 8
F(7) = 13
Program received signal SIGSEGV, Segmentation fault.
0x00000000004008db in listyAdd (p=0x6036a0, q=0x6036e0) at main.c:117
117 temp->next->digit += ptemp->digit;
(Okay, that's not all of it, but that's the relevant bit.)
What those last three lines mean is that you got a segfault. There are a bunch of things that can cause it, but based on that line, it looks like it's been caused by trying to dereference an invalid pointer. That's either a NULL pointer (a value of 0x0) or a pointer you've already freed.
If you're on Linux, you can then run Valgrind on it to figure out what, exactly, happened. It'll tell you if it's using a freed pointer or a NULL one, and that'll give you a good starting point to find the actual bug. You can also use your IDE's debugger (or GDB, if you want to try playing with the command-line version, but I wouldn't recommend it) to step through your program and see what the values of the variables involved are, which you can walk backwards from to see where they're being changed and invalidated.
If I had to guess, though, I'd say 0andriy's comments hit it on the nose -- you seem to be freeing things twice, and you probably meant to free them once, at the end.
I'm somewhat intentionally leaving this vague. Segfaults are common and (as you've noticed) difficult to debug, and you can only really learn how through experience. I think being shown the answer would honestly be less helpful than working through it yourself, and with tools like Valgrind and your debugger, that's not actually that hard, just tedious.
I found the issue. It was because the length of my linked lists weren't being reset when fib() was called. Thanks for your help everyone.
I'm trying to write an implementation for a Red Black Tree algorithm in C but after executing function insert() I get a crash and program stops working. This function firstly find a place in which new value should be added and then it execute another function called Correct_Tree which is responsible for correcting nodes with right order and colors.
There are few warnings I get but don't know how too fix them, other functions built in same way work fine.
|69|warning: conflicting types for 'correct_tree' [enabled by default]|
|40|note: previous implicit declaration of 'correct_tree' was here|
Same warnings point to function Rot_L, I don't know if this warnings cause my crashes. I will be thankful for every answer, if you need more information, let me know. Sorry for my english, I'm not a native speaker.
Here are these functions: http://ideone.com/hsYyES
and structure looks like this:
struct node {
int value;
int key_amounts;
char color;
struct node *parent;
struct node *left;
struct node *right;
} *root;
int insert(int n, struct node *start) {
//if node doesnt exist then add it to the tree otherwise increase amount of keys
//if tree is empty add root
if (root == NULL) {
root = (struct node*)malloc(sizeof *root);
root->value = n;
root->keys_amount = 0;
root->left = NULL;
root->right = NULL;
root->up = NULL;
} else
if (search(root, n) != NULL) {
struct node *tmp = search(root, n);
tmp->keys_amount += 1;
return 0;
} else
//if value is lower than root val then go to left son
if (n < start->value) {
//if left son exist then apply function insert for it
if (start->left != NULL) {
insert(n, start->left);
} else {
//if it doesnt exist then create
struct node *new = (struct node*)malloc(sizeof *root);
new->value = n;
new->keys_amount = 0;
new->left = NULL;
new->right = NULL;
new->up = start;
start->left = new;
correct_tree(new);
}
} else {
//if new value is higher than root
//if right son exist then apply function for it
if (start->right != NULL) {
insert(n, start->right);
} else {
//if it doesnt exist create new one
struct node *new = (struct node*)malloc(sizeof *root);
new->value = n;
new->keys_amount = 0;
new->left = NULL;
new->right = NULL;
new->up = start;
start->right = new;
correct_tree(new);
}
}
return 0;
}
//////////////////////////////////////////////////////////////////
void correct_tree(struct node *start) {
struct node *tmp = (struct node*)malloc(sizeof *root);
start->color = 'R';
while ((start != root) && (start->up->color == 'R')) {
if (start->up == start->up->up->left) {
tmp = start->up->up->right; //uncle of start for tmp
if (tmp->color == 'R') { //case 1
start->up->color = 'B';
tmp->color = 'B';
start->up->up->color='R';
start = start->up->up;
continue;
}
if (start == start->up->right) { //case 2
start = start->up;
rot_L(start);
}
start->up->color = 'B'; //case3
start->up->up->color = 'R';
rot_R(start->up->up);
break;
} else { //mirror cases
tmp = start->up->up->left;
if (tmp->color == 'R') { //case 1
start->up->color = 'B';
tmp->color = 'B';
start->up->up->color = 'R';
start = start->up->up;
continue;
}
if (start == start->up->left) { //case 2
start = start->up;
rot_R(start);
}
start->up->color = 'B'; //case3
start->up->up->color = 'R';
rot_L(start->up->up);
break;
}
}
root->color = 'B';
}
//////////////////////////////////////////////////////////////
void rot_L(struct node *start) {
struct node *tmp = (struct node*)malloc(sizeof *root);
struct node *tmp2 = (struct node*)malloc(sizeof *root);
tmp = start->right;
if (tmp != NULL) {
tmp2 = start->up;
start->right = tmp->left;
if (start->right != NULL)
start->right->up = start;
tmp->left = start;
tmp->up = tmp2;
start->up = tmp;
if (tmp2 != NULL) {
if (tmp2->left == start)
tmp2->left = tmp;
else
tmp2->right = tmp;
} else
root = tmp;
}
}
The warnings issued by the compiler tell you that you did not declare nor define correct_node before calling it. The prototype inferred by the compiler from the call is int correct_tree(struct node *start); which is incompatible with the actual definition it encounters later: void correct_tree(struct node *start). Same problem for rot_L(). Declare all functions before calling them.
Function correct_node is bound to fail because you dereference the up links without first checking that they are not NULL. For example the first time you call correct_node on theleftorrightchild of theroot` node, you have:
start->color = 'R';
while ((start != root) && (start->up->color == 'R')) {
if (start->up == start->up->up->left) {
You do not initialize the color of the root node allocated by malloc(). There is a small chance that root->color may be equal to 'R', which will cause start->up->up->left to have undefined behavior as start->up->up is NULL.
Another issue is this:
struct node *tmp = (struct node*)malloc(sizeof *root);
The object allocated for tmp is never used, never freed and tmp is overwritten in the loop. This is a blatant case of memory leak.
The same issue is present twice in rot_L, for tmp and tmp2.
refering to the question Deallocating binary-tree structure in C
struct Node{
Node *parent;
Node *next;
Node *child;
}
I tried to free a binary tree. The problem I have is the allocated objects are 5520 and the number of calls to the free functions is 2747. I don't know why, it should really free and iterate all over the nodes in the tree, here is the code that I use
int number_of_iterations =0;
int number_of_deletions =0;
void removetree(Node *node)
{
number_of_iterations++;
while(node != NULL)
{
Node *temp = node;
if(node->child != NULL)
{
node = node->child;
temp->child = node->next;
node->next = temp;
}
else
{
node = node->next;
remove(temp);
number_of_deletions++
}
}
}
Number of iteration is 5440 and the number of deletions is 2747.
New Fixed code: is that code correct ?
const Node *next(const Node *node)
{
if (node == NULL) return NULL;
if (node->child) return node->child;
while (node && node->next == NULL) {
node = node->parent;
}
if (node) return node->next;
return NULL;
}
for ( p= ctx->obj_root; p; p = next(p)) {
free(p);
}
If your nodes do indeed contain valid parent pointers, then the whole thing can be done in a much more compact and readable fashion
void removetree(Node *node)
{
while (node != NULL)
{
Node *next = node->child;
/* If child subtree exists, we have to delete that child subtree
first. Once the child subtree is gone, we'll be able to delete
this node. At this moment, if child subtree exists, don't delete
anything yet - just descend into the child subtree */
node->child = NULL;
/* Setting child pointer to null at this early stage ensures that
when we emerge from child subtree back to this node again, we will
be aware of the fact that child subtree is gone */
if (next == NULL)
{ /* Child subtree does not exist - delete the current node,
and proceed to sibling node. If no sibling, the current
subtree is fully deleted - ascend to parent */
next = node->next != NULL ? node->next : node->parent;
remove(node); // or `free(node)`
}
node = next;
}
}
This is a binary tree! It's confusing people because of the names you have chosen, next is common in a linked list but the types are what matters and you have one node referencing exactly two identical nodes types and that's all that matters.
Taken from here: https://codegolf.stackexchange.com/a/489/15982 which you linked to. And I renamed left to child and right to next :)
void removetree(Node *root) {
struct Node * node = root;
struct Node * up = NULL;
while (node != NULL) {
if (node->child != NULL) {
struct Node * child = node->child;
node->child = up;
up = node;
node = child;
} else if (node->next != NULL) {
struct Node * next = node->next;
node->child = up;
node->next = NULL;
up = node;
node = next;
} else {
if (up == NULL) {
free(node);
node = NULL;
}
while (up != NULL) {
free(node);
if (up->next != NULL) {
node = up->next;
up->next = NULL;
break;
} else {
node = up;
up = up->child;
}
}
}
}
}
I know that this is an old post, but i hope my answer helps someone in the future.
Here is my implementation of BinaryTree and it's operations in c++ without recursion, the logics can be easily implemented in C.
Each node owns a pointer to the parent node to make things easier.
NOTE: the inorderPrint() function used for printing out the tree's content uses recursion.
#include<iostream>
template<typename T>
class BinaryTree
{
struct node
{
//the binary tree node consists of a parent node for making things easier as you'll see below
node(T t)
{
value = t;
}
~node() { }
struct node *parent = nullptr;
T value;
struct node *left = nullptr;
struct node *right = nullptr;
};
node* _root;
//gets inorder predecessor
node getMinimum(node* start)
{
while(start->left)
{
start = start->left;
}
return *start;
}
/*
this is the only code that uses recursion
to print the inorder traversal of the binary tree
*/
void inorderTraversal(node* rootNode)
{
if (rootNode)
{
inorderTraversal(rootNode->left);
std::cout << rootNode->value<<" ";
inorderTraversal(rootNode->right);
}
}
int count;
public:
int Count()
{
return count;
}
void Insert(T val)
{
count++;
node* tempRoot = _root;
if (_root == nullptr)
{
_root = new node(val);
_root->parent = nullptr;
}
else
{
while (tempRoot)
{
if (tempRoot->value < val)
{
if (tempRoot->right)
tempRoot = tempRoot->right;
else
{
tempRoot->right = new node(val );
tempRoot->right->parent = tempRoot;
break;
}
}
else if (tempRoot->value > val)
{
if (tempRoot->left)
tempRoot = tempRoot->left;
else
{
tempRoot->left = new node(val);
tempRoot->left->parent = tempRoot;
break;
}
}
else
{
std::cout<<"value already exists";
count--;
}
}
}
}
void inorderPrint()
{
inorderTraversal(_root);
std::cout <<std::endl;
}
void Delete(T val)
{
node *tempRoot = _root;
//find the node with the value first
while (tempRoot!= nullptr)
{
if (tempRoot->value == val)
{
break;
}
if (tempRoot->value > val)
{
tempRoot = tempRoot->left;
}
else
{
tempRoot = tempRoot->right;
}
}
//if such node is found then delete that node
if (tempRoot)
{
//if it contains both left and right child replace the current node's value with inorder predecessor
if (tempRoot->right && tempRoot->left)
{
node inordPred = getMinimum(tempRoot->right);
Delete(inordPred.value);
count++;
tempRoot->value = inordPred.value;
}
else if (tempRoot->right)
{
/*if it only contains right child, then get the current node's parent
* check if the current node is the parent's left child or right child
* replace the respective pointer of the parent with the right child of the current node
*
* finally change the child's parent to the new parent
*/
if (tempRoot->parent)
{
if (tempRoot->parent->right == tempRoot)
{
tempRoot->parent->right = tempRoot->right;
}
if (tempRoot->parent->left == tempRoot)
{
tempRoot->parent->left = tempRoot->right;
}
tempRoot->right->parent = tempRoot->parent;
}
else
{
//if there is no parent then it's a root node
//root node should point to the current node's child
_root = tempRoot->right;
_root->parent = nullptr;
delete tempRoot;
}
}
else if (tempRoot->left)
{
/*
* same logic as we've done for the right node
*/
if (tempRoot->parent)
{
if (tempRoot->parent->right == tempRoot)
{
tempRoot->parent->right = tempRoot->left;
}
if (tempRoot->parent->left == tempRoot)
{
tempRoot->parent->left = tempRoot->left;
}
tempRoot->left->parent =tempRoot->parent ;
}
else
{
_root = tempRoot->left;
_root->parent = nullptr;
delete tempRoot;
}
}
else
{
/*
* if it's a leaf node, then check which ptr (left or right) of the parent is pointing to
* the pointer to be deleted (tempRoot)
* then replace that pointer with a nullptr
* then delete the (tempRoot)
*/
if (tempRoot->parent)
{
if (tempRoot->parent->right == tempRoot)
{
tempRoot->parent->right = nullptr;
}
else if (tempRoot->parent->left == tempRoot)
{
tempRoot->parent->left = nullptr;
}
delete tempRoot;
}
else
{
//if the leaf node is a root node ,then delete it and set it to null
delete _root;
_root = nullptr;
}
}
count--;
}
else
{
std::cout << "No element found";
}
}
void freeTree()
{
//the output it produces will be that of a preorder traversal
std::cout << "freeing tree:";
node* end=_root;
node* parent=nullptr;
while (end)
{
//go to the node with least value
if (end->left)
end = end->left;
else if (end->right)
{
//if it's already at the least value, then check if it has a right sub tree
//if it does then set it as "end" ptr so that the loop will check for the least node in this subtree
end = end->right;
}
else
{
//if it's a leaf node then it should be deleted and it's parent's (left or right pointer )
//should be safely set to nullptr
//then end should be set to the parent pointer
//so that it we can repeat the process for all other nodes that's left
std::cout << end->value<<" ";
parent = end->parent;
if (parent)
{
if (parent->left == end)
parent->left = nullptr;
else
parent->right = nullptr;
delete end;
}
else
{
delete end;
_root = nullptr;
}
count--;
end = parent;
}
}
}
~BinaryTree()
{
freeTree();
}
};
int main()
{
BinaryTree<int> bt;
bt.Insert(3);
bt.Insert(2);
bt.Insert(1);
bt.Insert(5);
bt.Insert(4);
bt.Insert(6);
std::cout << "before deletion:\n";
bt.inorderPrint();
bt.Delete(5);
bt.Delete(2);
bt.Delete(1);
bt.Delete(4);
std::cout << "after deletion:\n";
bt.inorderPrint();
bt.freeTree();
std::cout << "\nCount: " << bt.Count()<<"\n";
}
output:
before deletion:
1 2 3 4 5 6
after deletion:
3 6
freeing tree:6 3
Count: 0
freeing tree:
First to say is that if you try to solve a recursive problem in a non-recursive way, you'll run into trouble.
I have seen a wrong answer selected as the good one, so I'll try to show my approach:
I'll begin using pointer references instead of plain pointers, as passing a root pointer reference makes it easier to detect (and update) the pointers to the root node. So the interface to the routine will be:
void delete_tree(struct node * * const ref);
It represents a reference to the pointer that points to the root node. I'll descend to the node and, if one of child or next is NULL then this node can be freely eliminated by just making the referenced pointer to point to the other link (so I'll not lose it). If the node has two children (child and next are both != NULL) then I cannot delete this node until one of the branches has collapsed, and then I select one of the branches and move the reference (I declared the ref parameter const to assure I don't modify it, so I use another moving reference for this)
struct node **moving_reference;
Then, the algorithm follows:
void tree_delete(struct node ** const static_ref)
{
while (*static_ref) {
struct node **moving_ref = static_ref;
while (*moving_ref) {
struct node *to_be_deleted = NULL;
if ((*moving_ref)->child && (*moving_ref)->next) {
/* we have both children, we cannot delete until
* ulterior pass. Just move the reference. */
moving_ref = &(*moving_ref)->child;
} else if ((*moving_ref)->child) {
/* not both != NULL and child != NULL,
* so next == NULL */
to_be_deleted = *moving_ref;
*moving_ref = to_be_deleted->child;
} else {
/* not both != NULL and child == NULL,
* so follow next */
to_be_deleted = *moving_ref;
*moving_ref = to_be_deleted->next;
} /* if, else if */
/* now, delete the unlinked node, if available */
if (to_be_deleted) node_delete(to_be_deleted);
} /* while (*moving_ref) */
} /* while (*static_ref) */
} /* delete_tree */
I have included this algorithm in a complete example, showing you the partial trees and the position of moving_ref as it moves through the tree. It also shows the passes needed to delete it.
#include <stdio.h>
#include <stdlib.h>
#define N 100
#define D(x) __FILE__":%d:%s: " x, __LINE__, __func__
#define ASSERT(x) do { \
int res; \
printf(D("ASSERT: (" #x ") ==> %s\n"), \
(res = (int)(x)) ? "TRUE" : "FALSE"); \
if (!res) exit(EXIT_FAILURE); \
} while (0)
struct node {
int key;
struct node *child;
struct node *next;
}; /* struct node */
struct node *node_alloc(void);
void node_delete(struct node *n);
/* This routine has been written recursively to show the simplicity
* of traversing the tree when you can use recursive algorithms. */
void tree_traverse(struct node *n, struct node *p, int lvl)
{
while(n) {
printf(D("%*s[%d]\n"), lvl<<2, p && p == n ? ">" : "", n->key);
tree_traverse(n->child, p, lvl+1);
n = n->next;
} /* while */
} /* tree_traverse */
void tree_delete(struct node ** const static_ref)
{
int pass;
printf(D("BEGIN\n"));
for (pass = 1; *static_ref; pass++) {
struct node **moving_ref = static_ref;
printf(D("Pass #%d: Considering node %d:\n"),
pass, (*moving_ref)->key);
while (*moving_ref) {
struct node *to_be_deleted = NULL;
/* print the tree before deciding what to do. */
tree_traverse(*static_ref, *moving_ref, 0);
if ((*moving_ref)->child && (*moving_ref)->next) {
printf(D("Cannot remove, Node [%d] has both children, "
"skip to 'child'\n"),
(*moving_ref)->key);
/* we have both children, we cannot delete until
* ulterior pass. Just move the reference. */
moving_ref = &(*moving_ref)->child;
} else if ((*moving_ref)->child) {
/* not both != NULL and child != NULL,
* so next == NULL */
to_be_deleted = *moving_ref;
printf(D("Deleting [%d], link through 'child' pointer\n"),
to_be_deleted->key);
*moving_ref = to_be_deleted->child;
} else {
/* not both != NULL and child != NULL,
* so follow next */
to_be_deleted = *moving_ref;
printf(D("Deleting [%d], link through 'next' pointer\n"),
to_be_deleted->key);
*moving_ref = to_be_deleted->next;
} /* if, else if */
/* now, delete the unlinked node, if available */
if (to_be_deleted) node_delete(to_be_deleted);
} /* while (*moving_ref) */
printf(D("Pass #%d end.\n"), pass);
} /* for */
printf(D("END.\n"));
} /* delete_tree */
struct node heap[N] = {0};
size_t allocated = 0;
size_t deleted = 0;
/* simple allocation/free routines, normally use malloc(3). */
struct node *node_alloc()
{
return heap + allocated++;
} /* node_alloc */
void node_delete(struct node *n)
{
if (n->key == -1) {
fprintf(stderr,
D("doubly freed node %ld\n"),
(n - heap));
}
n->key = -1;
n->child = n->next = NULL;
deleted++;
} /* node_delete */
/* main simulation program. */
int main()
{
size_t i;
printf(D("Allocating %d nodes...\n"), N);
for (i = 0; i < N; i++) {
struct node *n;
n = node_alloc(); /* the node */
n->key = i;
n->next = NULL;
n->child = NULL;
printf(D("Node %d"), n->key);
if (i) { /* when we have more than one node */
/* get a parent for it. */
struct node *p = heap + (rand() % i);
printf(", parent %d", p->key);
/* insert as a child of the parent */
n->next = p->child;
p->child = n;
} /* if */
printf("\n");
} /* for */
struct node *root = heap;
ASSERT(allocated == N);
ASSERT(deleted == 0);
printf(D("Complete tree:\n"));
tree_traverse(root, NULL, 0);
tree_delete(&root);
ASSERT(allocated == N);
ASSERT(deleted == N);
} /* main */
Why not just do this recurisively?
void removetree(Node *node) {
if (node == NULL) {
return;
}
number_of_iterations++;
removetree(node->next);
removetree(node->child);
free(node);
number_of_deletions++;
}
The implementation does not work for a tree with root 1, which has a single child 2.
NodeOne.parent = null
NodeOne.next = null
NodeOne.child = NodeTwo
NodeTwo.parent = null
NodeTwo.next = null
NodeTwo.child = null
Execution of Removetree(NodeOne) will not call remove on NodeOne.
I would do
void removeTree(Node *node){
Node *temp;
while (node !=NULL){
if (node->child != NULL) {
removeTree(node->child);
}
temp = node;
node = node->next;
free(temp);
}
}
Non-recursive version:
void removeTree(Node *node){
Node *temp;
while (node !=NULL){
temp = node;
while(temp != node) {
for(;temp->child == NULL; temp = temp->child); //Go to the leaf
if (temp->next == NULL)
free(temp); //free the leaf
else { // If there is a next move it to the child an repeat
temp->child = temp->next;
temp->next = temp->next->next;
}
}
node = temp->next; // Move to the next
free(temp)
}
}
I think this should work
You are freeing only subtrees, not parent nodes. Suppose child represents the left child of the node and next is the right child. Then, your code becomes:
struct Node{
Node *parent;
Node *right;
Node *left;
}
int number_of_iterations =0;
int number_of_deletions =0;
void removetree(Node *node)
{
number_of_iterations++;
while(node != NULL)
{
Node *temp = node;
if(node->left != NULL)
{
node = node->left;
temp->left = node->right;
node->right = temp;
}
else
{
node = node->right;
remove(temp);
number_of_deletions++
}
}
}
Each time your while loop finishes one iteration, a left sub-node will be left without a pointer to it.
Take, for example the following tree:
1
2 3
4 5 6 7
When node is the root node, the following happens
node is pointing to '1'
temp is pointing to '1'
node now points to '2'
temp->left now points to '5'
node->right now points to '1'
In the next iteration, you begin with
node pointing to '2' and temp also. As you can see, you did not remove node '1'. This will repeat.
In order to fix this, you might want to consider using BFS and a queue-like structure to remove all the nodes if you want to avoid recursion.
Edit
BFS way:
Create a Queue structure Q
Add the root node node to Q
Add left node of node to Q
Add right node of node to Q
Free node and remove it from Q
Set node = first element of Q
Repeat steps 3-6 until Q becomes empty
This uses the fact that queue is a FIFO structure.
Code that was proposed by #AnT is incorrect, because it frees node right after traversing and freeing its left subtree but before doing the same with the right subtree. So, on ascending from the right subtree we'll step on the parent node that was already freed.
This is a correct approach, in C89. It still requires the parent links, though.
void igena_avl_subtree_free( igena_avl_node_p root ) {
igena_avl_node_p next_node;
{
while (root != NULL) {
if (root->left != NULL) {
next_node = root->left;
root->left = NULL;
} else if (root->right != NULL) {
next_node = root->right;
root->right = NULL;
} else {
next_node = root->parent;
free( root );
}
root = next_node;
}
}}
Taken directly from my own project Gena.