AVL Tree in C with iterative insertion - c

I'm coding a generic AVL tree as both a challenge to myself and, if I can do it properly, a resource for other CS students out there.
As one usually would, I started by implementing a recursive insertion function, which works. However, due to efficiency, I tried to implement the same function, but iteratively. I searched online and found lots of implementations, but the rest of the code was always too different from mine, which led me to continue attempting to create an implementation from scratch.
These are the relevant defined types:
typedef struct info {
int id;
char name[200];
} data;
typedef struct avl_node {
void * data;
struct avl_node * left;
struct avl_node * right;
int height;
} * avl_node_t;
typedef struct avl_tree {
avl_node_t root;
int num_nodes;
int (*less)(const void * first, const void * second);
int (*key)(const void * data);
} * avl_t;
And as follows is the iterative insertion function (which doesn't work as intended):
avl_node_t
avl_insert(avl_node_t node, void * data)
{
long key1 = 0, key2 = 0;
avl_node_t aux = NULL;
while (1) {
if (node == NULL) {
node = avl_node_create(data);
break;
}
key1 = key((void*)&data);
key2 = key((void*)&(node->data));
aux = node;
if (less((void*)&key1, (void*)&key2))
node = node->left;
else
node = node->right;
}
if (aux != NULL) {
if (less((void*)&key1, (void*)&key2))
aux->right = node;
else if (less((void*)&key2, (void*)&key1))
aux->left = node;
}
node = avl_balance(node);
return node;
}
In which the avl_balance function is defined as such:
static short
balance(avl_node_t node)
{
if (node == NULL)
return 0;
return avl_node_height(node->left) - avl_node_height(node->right);
}
static avl_node_t
avl_balance(avl_node_t node)
{
short balance_factor;
if (node == NULL)
return node;
balance_factor = balance(node);
if (balance_factor > 1)
if (balance(node->left) >= 0)
node = avl_rotRight(node);
else
node = avl_rotLeftRight(node);
else if (balance_factor < -1)
if (balance(node->right) <= 0)
node = avl_rotLeft(node);
else
node = avl_rotRightLeft(node);
else
update_height(node);
return node;
}
This is the code I'm using to test the AVL tree:
int main()
{
data d1 = { 1, "we are number one" };
data d2 = { 2, "boneless pizza" };
data d3 = { 3, "hehe" };
data d4 = { 4, "achoo" };
data d5 = { 5, "I like C" };
data d6 = { 6, "Assembly is cool too" };
data d7 = { 7, "SIGSEGV" };
avl_t tree = avl_create();
avl_node_t root = tree->root;
root = avl_insert(root, (void*)&d1);
traverse(root);
root = avl_insert(root, (void*)&d2);
traverse(root);
root = avl_insert(root, (void*)&d3);
root = avl_insert(root, (void*)&d4);
root = avl_insert(root, (void*)&d5);
root = avl_insert(root, (void*)&d6);
root = avl_insert(root, (void*)&d7);
traverse(root);
free(tree);
exit(0);
}
In which traverse is defined as such:
void visit(void * d)
{
data * my_data = (data*)d;
printf("I am element number %d named %s\n", (*my_data).id, (*my_data).name);
fflush(stdout);
}
void traverse(avl_node_t node)
{
if (node == NULL)
return;
traverse(node->left);
traverse(node->right);
visit(node->data);
}
And finally, this is the output I'm getting from this test:
I am element number 1 named we are number one
I am element number 2 named boneless pizza
I am element number 7 named SIGSEGV
Thank you in advance.

If you do not mind, i implemented it in c++ version.
// In the view of C, just omit the template declaration and replace the class with struct
template<typename T>
class AVL_tree{
private:
class AVL_Node{
public:
T val;
AVL_Node* left;
AVL_Node* right;
AVL_Node* parent;
int height;
// Node Constructor -
AVL_Node():left{nullptr}, right{nullptr}, parent{nullptr}, val{}, height{0}{}
AVL_Node(T val): left{nullptr}, right{nullptr}, parent{nullptr}, height{0}, val{val}{}
};
AVL_Node* root;
short (*cmp_func)(T, T);
// Utility -
void add_child(AVL_Node* prev_nd, AVL_Node* chd_nd){
if(prev_nd == nullptr){
this->root = chd_nd;
return;
}
// update parent pointer first.
switch(cmp_func(chd_nd->val, prev_nd->val)){
case 1:
prev_nd->right = chd_nd;
break;
case 0:
prev_nd->left = chd_nd;
break;
case -1:
cerr << "Warning : The element should not be duplicate." << endl;
return;
default:
cerr << "ERROR_MESSAGE : The self-defin compare func should return triple value (1, 0, -1)." << endl;
return;
}
// update parent pointer of child node
chd_nd->parent = prev_nd;
}
AVL_Node* find_node(T val){
AVL_Node* prev_ptr = nullptr;
for(AVL_Node* tmp_ptr = this->root ; tmp_ptr != nullptr ; ){
prev_ptr = tmp_ptr;
switch(cmp_func(val, tmp_ptr->val)){
case 1:
tmp_ptr = tmp_ptr->right;
break;
case 0:
tmp_ptr = tmp_ptr->left;
break;
case -1:
return prev_ptr;
}
}
// for not find the node, return their parent node.
return prev_ptr;
}
int get_max(int a, int b){ return (a >= b) ? a : b; }
int get_height(AVL_Node* ptr_nd){
if(ptr_nd == nullptr)
return -1;
return ptr_nd->height;
}
int cal_balance(AVL_Node* nd_ptr){ return get_height(nd_ptr->left) - get_height(nd_ptr->right); }
AVL_Node* Right_rotate(AVL_Node* curr_nd){
AVL_Node* lft_chd = curr_nd->left;
AVL_Node* rgt_suc = lft_chd->right;
// Perform rotation
lft_chd->right = curr_nd;
curr_nd->left = rgt_suc;
// update parent pointer of current pointed node and child node
lft_chd->parent = curr_nd->parent;
curr_nd->parent = lft_chd;
if(rgt_suc != nullptr)
rgt_suc->parent = curr_nd;
// Update heights
lft_chd->height = get_max(get_height(lft_chd->left), get_height(lft_chd->right)) + 1;
curr_nd->height = get_max(get_height(curr_nd->left), get_height(curr_nd->right)) + 1;
return lft_chd;
}
AVL_Node* Left_rotate(AVL_Node* curr_nd){
AVL_Node* rgt_chd = curr_nd->right;
AVL_Node* lft_suc = rgt_chd->left;
// Perform rotation
rgt_chd->left = curr_nd;
curr_nd->right = lft_suc;
// update parent pointer of current pointed node and child node
rgt_chd->parent = curr_nd->parent;
curr_nd->parent = rgt_chd;
if(lft_suc != nullptr)
lft_suc->parent = curr_nd;
// Update heights
rgt_chd->height = get_max(get_height(rgt_chd->left), get_height(rgt_chd->right)) + 1;
curr_nd->height = get_max(get_height(curr_nd->left), get_height(curr_nd->right)) + 1;
return rgt_chd;
}
void splice(AVL_Node* ptr_nd){
/* remove node confirm that the ptr_nd have successor in single side.
Case 1. ; Case 2. */
AVL_Node* succsor_nd = (ptr_nd->left != nullptr) ? ptr_nd->left : ptr_nd->right;
if(ptr_nd == this->root){ // for remove the root.
this->root = succsor_nd;
}else{
AVL_Node* par_nd = ptr_nd->parent;
if(par_nd->left == ptr_nd)
par_nd->left = succsor_nd;
else
par_nd->right = succsor_nd;
if(succsor_nd != nullptr) succsor_nd->parent = par_nd;
}
}
public:
enum Order{ // for the order traversal.
pre_order,
post_order,
in_order
};
// Constructor -
AVL_tree():root{nullptr}, cmp_func{&defau_cmp<T>}{}
AVL_tree(short (*def_cmp_func)(T, T)):root{nullptr}, cmp_func{def_cmp_func}{}
// Operation -
void insert(T val){
// BST insertion operation
AVL_Node* prev_nd = find_node(val);
AVL_Node* chd_nd = new AVL_Node(val);
add_child(prev_nd, chd_nd);
// Balance the tree
for(AVL_Node* nd_ptr = prev_nd ; nd_ptr != nullptr ; nd_ptr = nd_ptr->parent){
const int& bf = cal_balance(nd_ptr);
// Left bias unbalance
if( bf > 1 ){
if(val > nd_ptr->left->val)
nd_ptr->left = Left_rotate(nd_ptr->left);
// update parent's pointer
AVL_Node* par_ptr = nd_ptr->parent;
if(par_ptr != nullptr && par_ptr->right == nd_ptr)
par_ptr->right = Right_rotate(nd_ptr);
else if(par_ptr != nullptr && par_ptr->left == nd_ptr)
par_ptr->left = Right_rotate(nd_ptr);
else
Right_rotate(nd_ptr);
// Right bias unbalance
}else if(bf < -1){
if(val < nd_ptr->right->val)
nd_ptr->right = Right_rotate(nd_ptr->right);
// update parent's pointer
AVL_Node* par_ptr = nd_ptr->parent;
if(par_ptr != nullptr && par_ptr->right == nd_ptr)
par_ptr->right = Left_rotate(nd_ptr);
else if(par_ptr != nullptr && par_ptr->left == nd_ptr)
par_ptr->left = Left_rotate(nd_ptr);
else // nd_ptr equal root
Left_rotate(nd_ptr);
// else, the sub-tree is already balanced
}else{
nd_ptr->height = get_max(get_height(nd_ptr->left), get_height(nd_ptr->right)) + 1;
}
// finally update the new root pointer
if(nd_ptr->parent == nullptr)
this->root = nd_ptr;
}
}
// remove operation is still working on it though.
// Smart_queue just like a queue offer general interface, you can use stl-container.
void BF_print(){
Smart_queue<AVL_Node*> nd_que(this->root);
while(!nd_que.is_empty()){
AVL_Node* tmp_ptr = nd_que.pop();
if(tmp_ptr == nullptr)
continue;
cout << tmp_ptr->val << " ";
nd_que.push(tmp_ptr->left);
nd_que.push(tmp_ptr->right);
}
}
};

Related

Getting Segmentation fault in C code while trying to assign a pointer to some object

I am trying to solve a question in C language. The problem statement is(reading whole problem is not important for my doubt):
Given an arbitrary unweighted rooted tree which consists of N nodes.
The goal of the problem is to find largest distance between two nodes in a tree.
Distance between two nodes is a number of edges on a path between the nodes (there will be a unique path between any pair of nodes since it is a tree).
The nodes will be numbered 0 through N - 1.
The tree is given as an array A, there is an edge between nodes A[i] and i (0 <= i < N). Exactly one of the i's will have A[i] equal to -1, it will be root node.
I made TreeNode and I am storing all next connections TreeNode pointers in array(like adjacency list in graph)
My solution is:
/**
* #input A : Integer array
* #input n1 : Integer array's ( A ) length
*
* #Output Integer
*/
struct TreeNode2 {
int value;
struct TreeNode2 *next;
};
struct TreeNode2* createNode(int n)
{
struct TreeNode2 *node = (struct TreeNode2 *)calloc(1, sizeof(struct TreeNode2));
node->value = n;
node->next = NULL;
return node;
}
int maximum(int a,int b)
{
if(a>b)
return a;
return b;
}
int dfs(struct TreeNode2 **tree, int node)
{
if( tree[node] == NULL )
return 0;
int len1 = 0;
int len2 = 0;
struct TreeNode2 *ptr = tree[node];
while(ptr!=NULL)
{
int curr = dfs(tree, (ptr->value));
if( curr > len1 )
{
len1 = curr;
}
else if(curr > len2)
{
len2 = curr;
}
ptr = ptr->next;
}
return maximum( len1 + len2 , maximum( len1 , len2 ) + 1 );
}
int solve(int* A, int n1)
{
struct TreeNode2 *tree[n1];
int i=0;
for(i=0;i<n1;i++)
{
tree[i] = NULL;
}
for(i=0;i<n1;i++)
{
if(A[i] != -1)
{
struct TreeNode2 *temp = tree[i];
struct TreeNode2 *newNode = createNode(A[i]);
tree[i] = newNode;
newNode->next = temp;
// printf("A[i] = %d \n",A[i]);
struct TreeNode2 *temp2 = tree[ A[i] ];
struct TreeNode2 *newNode2 = createNode(i);
tree[ A[i] ] = newNode2;
newNode2->next = temp2;
}
}
int ans = dfs(tree, 0);
return ans;
}
I'm getting the segmentation fault the moment I am adding
tree[ A[i] ] = newNode2;
in solve function in forloop for input -1, 0. I tried tree[A[i]] = NULL (it worked). The problem is when A[i] = 0, tree[0] = NULL is working but tree[0] = newNode2 is not working why.?
Finally I caught the problem, actually in this problem tree connection is undirected so the code is stuck in loop inside dfs. I used visited array to solve this issue.
From the link, the example explanation shows that node 0 has three [direct] children (nodes, 1, 2, 3).
I could be wrong about this, but I think an algorithm that works is as follows:
As we build the tree, we remember the node with the maximum depth.
After the tree is built, we can traverse it to find the maximum depth of any [leaf] node that is not max node we found when building.
The solution is the sum of the depth of those two nodes
Here's some code I wrote to do that. I submitted it for test input and it passed.
Edit: I've revised the test and now it passes all tests but exceeds the time limit in the "Efficiency" test.
I expected as much because of the [seeming] O(n^2) but I wanted to try a non-standard approach that doesn't use "visited".
I added some code to dump a text file that can be fed to graphviz with -DGRAPH. It produces an output file: grf. To process this, do:
dot -Tsvg < grf > grf.svg
Then, you can point your browser to the grf.svg file to display the graph.
Anyway, here's the working but slow code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define sysfault(_fmt...) \
do { \
printf(_fmt); \
exit(1); \
} while (0)
#ifndef ROOTLEAF
#define ROOTLEAF 0
#endif
#if ROOTLEAF
#define PTROK(_ptr) (_ptr != NULL)
#else
#define PTROK(_ptr) 1
#endif
#ifdef DEBUG
#define dbgprt(_fmt...) \
do { \
printf(_fmt); \
} while (0)
#define nodeshow(_node,_tag) \
do { \
_nodeshow(_node,_tag); \
} while (0)
#ifndef GRAPH
#define GRAPH
#endif
#else
#define dbgprt(_fmt...) \
do { \
} while (0)
#define nodeshow(_node,_tag) \
do { \
} while (0)
#endif
#define MAXNODE 40000
#define COUNTOF(_arr) \
(sizeof(_arr) / sizeof(_arr[0]))
typedef struct node node_t;
struct node {
int paridx;
int depth;
node_t *parent;
node_t *next;
node_t *cldhead;
node_t *cldtail;
node_t *leaf;
};
static node_t *root = NULL;
static node_t *lhsbest = NULL;
static node_t *rhsbest = NULL;
static int Acnt = -1;
static node_t nodelist[MAXNODE + 1] = { 0 };
static int soldepth;
static FILE *xfgrf;
static char *
tlsbuf(void)
{
static int bufidx = 0;
static char buf[16][1000];
char *bp;
bp = buf[bufidx];
++bufidx;
bufidx %= 16;
*bp = 0;
return bp;
}
static int
nodenum(node_t *node)
{
if (node != NULL)
return node - nodelist;
else
return -1;
}
static char *
nodexid(node_t *lhs,node_t *rhs)
{
int lhsnum = nodenum(lhs);
int rhsnum = nodenum(rhs);
int tmp;
char *buf;
if (lhsnum > rhsnum) {
tmp = lhsnum;
lhsnum = rhsnum;
rhsnum = tmp;
}
buf = tlsbuf();
sprintf(buf,"%d,%d",lhsnum,rhsnum);
return buf;
}
static void
_nodeshow(node_t *node,const char *tag)
{
#ifdef DEBUG
if (node != NULL) {
dbgprt("nodeshow: %s node=%d paridx=%d depth=%d\n",
tag,nodenum(node),node->paridx,node->depth);
}
else
dbgprt("nodeshow: %s null\n",tag);
#endif
}
// newnode -- create new node;
static node_t *
newnode(int idx,node_t *par)
{
node_t *node;
node = &nodelist[idx];
if (par != NULL) {
node->paridx = nodenum(par);
node->depth = par->depth + 1;
}
else
node->paridx = -1;
node->parent = par;
return node;
}
// fastfind -- find node based on i from A[i]
static node_t *
fastfind(int value)
{
node_t *node;
node = &nodelist[value];
nodeshow(node,"fastfind");
return node;
}
// addchild -- attach child node to parent
static void
addchild(node_t *par,node_t *cld)
{
cld->next = par->cldhead;
par->cldhead = cld;
}
int
pathok(node_t *cur)
{
int okay;
if (ROOTLEAF)
okay = (cur != NULL);
else
okay = (cur != NULL) && (cur != root);
return okay;
}
int
pathcost(node_t *lhs,node_t *rhs)
{
int lhsok;
int rhsok;
int cost;
dbgprt("pathcost: ENTER lhs=%d rhs=%d xid=%s\n",
nodenum(lhs),nodenum(rhs),nodexid(lhs,rhs));
cost = 0;
if (lhs == root) {
dbgprt("pathcost: QWKROOT\n");
cost = rhs->depth;
lhs = NULL;
rhs = NULL;
}
while (1) {
if ((lhs == NULL) && (rhs == NULL))
break;
// join at lower level than root
if (lhs == rhs)
break;
#ifdef DEBUG
nodeshow(lhs,"LHS");
nodeshow(rhs,"RHS");
#endif
lhsok = pathok(lhs);
rhsok = pathok(rhs);
if (PTROK(lhs) && PTROK(rhs) && (lhs->depth > rhs->depth)) {
//nodeshow(lhs,"LHSDEEP");
if (lhsok) {
cost += 1;
dbgprt("pathcost: LCOST/D cost=%d\n",cost);
lhs = lhs->parent;
}
continue;
}
if (PTROK(lhs) && PTROK(rhs) && (rhs->depth > lhs->depth)) {
//nodeshow(lhs,"RHSDEEP");
if (rhsok) {
cost += 1;
dbgprt("pathcost: RCOST/D cost=%d\n",cost);
rhs = rhs->parent;
}
continue;
}
if (PTROK(lhs) && lhsok) {
cost += 1;
dbgprt("pathcost: LCOST/S cost=%d\n",cost);
lhs = lhs->parent;
}
if (PTROK(rhs) && rhsok) {
cost += 1;
dbgprt("pathcost: RCOST/S cost=%d\n",cost);
rhs = rhs->parent;
}
}
dbgprt("pathcost: EXIT cost=%d\n",cost);
return cost;
}
void
search1(void)
{
int curcost;
node_t *end = &nodelist[Acnt];
node_t *leafbase = NULL;
node_t *lhs = NULL;
node_t *rhs = NULL;
int bestcost = 0;
int leafcnt = 0;
// link all leaf nodes together
for (rhs = nodelist; rhs < end; ++rhs) {
if (ROOTLEAF) {
if (rhs != nodelist) {
if (rhs->cldhead != NULL)
continue;
}
}
else {
if (rhs->cldhead != NULL)
continue;
}
nodeshow(rhs,"ISLEAF");
if (leafbase == NULL)
leafbase = rhs;
if (lhs != NULL)
lhs->leaf = rhs;
lhs = rhs;
++leafcnt;
}
lhsbest = NULL;
rhsbest = NULL;
do {
if (leafcnt == 1) {
bestcost = leafbase->depth;
lhsbest = leafbase;
break;
}
for (lhs = leafbase; lhs != NULL; lhs = lhs->leaf) {
nodeshow(lhs,"LEAFLHS");
for (rhs = lhs->leaf; rhs != NULL; rhs = rhs->leaf) {
curcost = pathcost(lhs,rhs);
if (curcost > bestcost) {
lhsbest = lhs;
nodeshow(lhsbest,"LHSGUD");
rhsbest = rhs;
nodeshow(rhsbest,"RHSGUD");
bestcost = curcost;
}
}
}
} while (0);
nodeshow(lhsbest,"LHSBEST");
nodeshow(rhsbest,"RHSBEST");
soldepth = bestcost;
}
int
pathcost2(node_t *lhs,node_t *rhs)
{
int lhsok;
int rhsok;
int cost;
dbgprt("pathcost2: ENTER lhs=%d rhs=%d xid=%s\n",
nodenum(lhs),nodenum(rhs),nodexid(lhs,rhs));
cost = 0;
if (lhs == root) {
dbgprt("pathcost: QWKROOT\n");
cost = rhs->depth;
lhs = NULL;
rhs = NULL;
}
while (1) {
if ((lhs == NULL) && (rhs == NULL))
break;
// join at lower level than root
if (lhs == rhs)
break;
#ifdef DEBUG
nodeshow(lhs,"LHS");
nodeshow(rhs,"RHS");
#endif
lhsok = pathok(lhs);
rhsok = pathok(rhs);
if (PTROK(lhs) && PTROK(rhs) && (lhs->depth > rhs->depth)) {
//nodeshow(lhs,"LHSDEEP");
if (lhsok) {
cost += 1;
dbgprt("pathcost: LCOST/D cost=%d\n",cost);
lhs = lhs->parent;
}
continue;
}
if (PTROK(lhs) && PTROK(rhs) && (rhs->depth > lhs->depth)) {
//nodeshow(lhs,"RHSDEEP");
if (rhsok) {
cost += 1;
dbgprt("pathcost: RCOST/D cost=%d\n",cost);
rhs = rhs->parent;
}
continue;
}
if (PTROK(lhs) && lhsok) {
cost += 1;
dbgprt("pathcost: LCOST/S cost=%d\n",cost);
lhs = lhs->parent;
}
if (PTROK(rhs) && rhsok) {
cost += 1;
dbgprt("pathcost: RCOST/S cost=%d\n",cost);
rhs = rhs->parent;
}
}
dbgprt("pathcost2: EXIT cost=%d\n",cost);
return cost;
}
void
search2(void)
{
int curcost;
node_t *end = &nodelist[Acnt];
node_t *leafbase = NULL;
node_t *lhs = NULL;
node_t *rhs = NULL;
int bestcost = 0;
int leafcnt = 0;
int maxdepth = 0;
lhsbest = NULL;
rhsbest = NULL;
// link all leaf nodes together
for (rhs = nodelist; rhs < end; ++rhs) {
if (rhs->cldhead != NULL)
continue;
nodeshow(rhs,"ISLEAF");
if (rhs->depth > maxdepth) {
maxdepth = rhs->depth;
rhsbest = rhs;
}
if (leafbase == NULL)
leafbase = rhs;
if (lhs != NULL)
lhs->leaf = rhs;
lhs = rhs;
++leafcnt;
}
do {
bestcost = maxdepth;
lhsbest = leafbase;
if (leafcnt == 1) {
bestcost = leafbase->depth;
lhsbest = leafbase;
break;
}
for (lhs = leafbase; lhs != NULL; lhs = lhs->leaf) {
nodeshow(lhs,"LEAFLHS");
for (rhs = lhs->leaf; rhs != NULL; rhs = rhs->leaf) {
curcost = pathcost(lhs,rhs);
if (curcost > bestcost) {
lhsbest = lhs;
nodeshow(lhsbest,"LHSGUD");
rhsbest = rhs;
nodeshow(rhsbest,"RHSGUD");
bestcost = curcost;
}
}
}
} while (0);
nodeshow(lhsbest,"LHSBEST");
nodeshow(rhsbest,"RHSBEST");
soldepth = bestcost;
}
void
dograph(void)
{
#ifdef GRAPH
int idx;
node_t *cur;
node_t *par;
char *bp;
char buf[100];
xfgrf = fopen("grf","w");
fprintf(xfgrf,"digraph {\n");
for (idx = 0; idx < Acnt; ++idx) {
cur = &nodelist[idx];
bp = buf;
bp += sprintf(bp,"label=\"N%d D%d\"",nodenum(cur),cur->depth);
if (cur == rhsbest)
bp += sprintf(bp," color=Green");
if (cur == lhsbest)
bp += sprintf(bp," color=Red");
fprintf(xfgrf,"\tN%d [%s]\n",nodenum(cur),buf);
par = cur->parent;
if (par != NULL)
fprintf(xfgrf,"\tN%d -> N%d\n",nodenum(par),nodenum(cur));
}
fprintf(xfgrf,"}\n");
fclose(xfgrf);
#endif
}
int
solve(int *A,int argcnt)
{
int idx;
int parval;
node_t *par;
if (root != NULL) {
memset(nodelist,0,sizeof(nodelist));
root = NULL;
}
// find the root node
// FIXME/CAE -- probably always the first
Acnt = argcnt;
for (idx = 0; idx < Acnt; ++idx) {
int parval = A[idx];
if (parval == -1) {
dbgprt("solve: ROOT idx=%d\n",idx);
root = newnode(idx,NULL);
break;
}
}
// build all child nodes:
for (idx = 0; idx < Acnt; ++idx) {
parval = A[idx];
if (parval == -1)
continue;
dbgprt("solve: NODE idx=%d parval=%d\n",idx,parval);
// find parent
par = fastfind(parval);
// create node
node_t *cur = newnode(idx,par);
// attach child to parent
addchild(par,cur);
}
// traverse all nodes in the tree to find max distance ...
search2();
dograph();
return soldepth;
}

C :: Memory access violation randomly appears in Linked List

so here is the code that gives me headache :
void newCopy(ListNode* n, List* l) {
if (n == NULL) { return; }
if (n->next == NULL) {
push(n->data, l);
return;
}
else {
newCopy(n->next, l);
push(n->data, l);
return;
}
}
As you can see if n == NULL then the function is supposed to end but you see it coming : it's not ending the function.
I'm getting "read access violation" on if (n->next == NULL) because n is NULL.
I also get error randomly on other functions, all related to memory access.
The function you should investigate is State* progDynState(List* taskList) because everything is done here.
I know some people want minimal reproductible exemple, I can't produce one because everything is used, so here is the entire code.
File Main :
#include "Tools.h"
#include <time.h>
int main()
{
/* initialize random seed: */
srand(time(NULL));
//List creation
//
List* taskList = consList();
Task* task = NULL;
//Task number
/*int n = (rand() % 14 + 4);
//Generate random tasks
for(int i = 1; i <= n; i++) {
task = consTask(i + (rand() % 10 + 1) - rand() % 5 , i + (rand() % 10 + 1) - rand() % 5);
push(task, taskList);
}*/
for (int i = 1; i <= 4; i++) {
task = consTask(i,i);
push(task, taskList);
}
std::cout << "Display origin : \n" << listToString_Task(taskList) << " \n";
//--- CLASSIC ---
//SOLVE PROBLEM - PROG DYN STATE
State* opt = progDynState(taskList);
//--- FPTAS ---
double sigma = 1; //TO CHANGE DEPENDING ON PRECISION
//Get deltas
double deltaD = findDeltaD(taskList, sigma);
double deltaL = findDeltaL(taskList, sigma);
//Rounded values
List* rL = rounding(taskList, deltaD, deltaL);
//SOLVE PROBLEM - PROG DYN STATE
std::cout << "ROUNDED OPT : \n";
State* roundedOpt = progDynState(rL);
//Transpose the solution on the original instance
List* pair = createListTaskPair(taskList, rL);
State* FPTASopt = transpose(roundedOpt, pair);
std::cout << "Optimal Solution 2 : \n" << stateToString(FPTASopt) << " \n";
}
File ProblemElement.h
#pragma once
#include <string>
#include <iostream>
#include <sstream>
#include <cmath>
#include <algorithm>
#ifndef PROBLEM
#define PROBLEM
// -----------------------------------------------------//
// ------------------ LIST ------------------//
// -----------------------------------------------------//
typedef struct ListNode ListNode;
struct ListNode
{
void *data;
struct ListNode *next;
};
typedef struct List List;
struct List
{
struct ListNode *head;
struct ListNode *tail;
int size;
};
//Initialize a list's value
void empty(List* l);
//Create an empty list
List* consList() //allocate and initialize to NULL values
{
List* list = (List*)calloc(1,sizeof(List*));
while(list == NULL) list = (List*)calloc(1,sizeof(List*));
empty(list);
return list;
}
//Add data to the head of the list
void push(void *data, List *list)
{
if (list == NULL) return;
if (data == NULL) return;
ListNode *newNode = (ListNode*)calloc(1,sizeof(ListNode));
newNode->data = data;
newNode->next = list->head;
if (list->head == NULL) //the list is empty
{
list->head = newNode;
list->tail = list->head;
}
else
{
list->head = newNode;
}
list->size++;
}
//Add data to the tail of the list
void append(void *data, List *list)
{
if (list == NULL) return;
if (data == NULL) return;
ListNode *newNode = (ListNode*)calloc(1,sizeof(ListNode));
newNode->data = data;
newNode->next = NULL;
if (list->head == NULL) //the list is empty
{
list->head = newNode;
list->tail = list->head;
}
else
{
list->tail->next = newNode;
list->tail = newNode;
}
list->size++;
}
//Remove first element
void pop(List* l) {
if (l == NULL) return;
if (l->head->next == NULL) {
free(l->head);
empty(l);
}
else {
ListNode* ln = l->head;
l->head = ln->next;
free(ln);
}
l->size--;
}
void endPop(List* l) {
if (l == NULL) return;
if (l->head->next == NULL) {
pop(l);
}
else {
ListNode* curr = l->head;
ListNode* prev = NULL;
while (curr != l->tail) {
prev = curr;
curr = curr->next;
}
free(l->tail);
prev->next = NULL;
l->size--;
}
}
//Remove element contening data
void removeData(void *data, List *list){
if (data == NULL) return;
if (list == NULL) return;
if (list->head == NULL) return;
//Head to be removed
if (data == list->head->data) {
pop(list);
return;
}
//Tail to be removed
if (data == list->tail->data){
endPop(list);
return;
}
//Other node
ListNode* curr = list->head;
ListNode* prev = NULL;
while (curr->data != data) {
prev = curr;
curr = curr->next;
}
prev->next = curr->next;
free(curr);
list->size--;
}
//Make l1's head and tail point to l2's
void assignTo(List* l1, List* l2) {
if (l1 == NULL) return;
if (l2 == NULL) return;
l1->head = l2->head;
l1->tail = l2->tail;
l1->size = l2->size;
}
//Initialize a list's value
void empty(List* l) {
if (l == NULL) return;
l->head = NULL;
l->tail = NULL;
l->size = 0;
}
//Free memory of all nodes
void freeNodes(List* l) {
if (l == NULL) return;
if (l->head->next == NULL) {
pop(l);
return;
}
while (l->head != NULL) {
pop(l);
}
}
//Create a copy of n in l with new elements, shared data pointer
void newCopy(ListNode* n, List* l) {
if (n == NULL) { return; }
if (n->next == NULL) {
push(n->data, l);
return;
}
else {
newCopy(n->next, l);
push(n->data, l);
return;
}
}
// -----------------------------------------------------//
// ------------------ STATE ------------------//
// -----------------------------------------------------//
typedef struct State State;
struct State
{
double _eOe; //End of execution
double _t; //Start of next task on first machine
//First machine
List* _task1;
//Second machine
List* _task2;
};
//Constructor of State
State* consState(double eOe = 0, double t = 0) {
State* s = (State*)malloc(sizeof(State));
s->_t = t;
s->_eOe = eOe;
s->_task1 = consList();
s->_task2 = consList();
return s;
}
//Describe a list of task
std::string listToString_Task(List* tL);
//Describe a state
std::string stateToString(struct State * s) {
std::string st;
st += "State : ( t = " + std::to_string(s->_t) + " , eOe = " + std::to_string(s->_eOe) + " ) \n";
st += "Task on machine 1 : (" + listToString_Task(s->_task1) + ") \n";
st += "Task on machine 2 : (" + listToString_Task(s->_task2) + ") \n";
st += "End of execution : " + std::to_string(s->_eOe);
return st;
}
// -----------------------------------------------------//
// ------------------ TASK ------------------//
// -----------------------------------------------------//
typedef struct Task Task;
struct Task
{
double _dur;//task duration
double _lat;//task latency
};
//Constructor of Task
Task* consTask(double dur = 0, double lat = 0) {
Task* t = (Task*)malloc(sizeof(Task));
t->_dur = dur;
t->_lat = lat;
return t;
}
//Describe a task
std::string taskToString(struct Task * t) {
return "Task : ( _dur = " + std::to_string(t->_dur) + " , _lat = " + std::to_string(t->_lat) + " )";
}
// -----------------------------------------------------//
// ------------------ PAIR : TASK | ROUNDED TASK ------------------//
// -----------------------------------------------------//
typedef struct TaskPair TaskPair;
struct TaskPair
{
Task* _origin;//original Tasks
Task* _rounded;//rounded Tasks
};
//Constructor of TaskPair
TaskPair* consTaskPair(Task* origin, Task* rounded) {
TaskPair* t = (TaskPair*)malloc(sizeof(TaskPair));
t->_origin = origin;
t->_rounded = rounded;
return t;
}
//Describe a task
std::string taskPairToString(struct TaskPair * t) {
return "TaskPair : ( origin = " + taskToString(t->_origin) + " , rounded = " + taskToString(t->_rounded) + " )";
}
#endif // !PROBLEM
File Tools.h
#pragma once
#include "ProblemElements.h"
#ifndef TOOLS
#define TOOLS
// -----------------------------------------------------//
// ------------------ GENERAL TOOLS ------------------//
// -----------------------------------------------------//
std::string listToString_State(List* sL);
//Keeps only the best state of a PElement<State>.
List* keepBestState(List* sL) {
if (sL == NULL) return NULL;
if (sL->head->next == NULL) return sL;
std::cout << "Size : " << std::to_string(sL->size) << "\n";
std::cout << "sL : " << listToString_State(sL) << "\n";
State* currS = (State*)sL->head->data;
State* nextS = (State*)sL->head->next->data;
//Current element is better, removing following element | Following element is better, removing current element
if(currS->_eOe <= nextS->_eOe)
removeData(sL->head->next->data, sL);
else
pop(sL);
return keepBestState(sL);
}
//Split List in two half
void splitList(List* sL, List* half2) {
//Size of list to sort
int listSize = sL->size;
//Half of size list
if (listSize % 2 == 0) {
listSize = listSize / 2;
sL->size = listSize;
half2->size = listSize;
}
else {
listSize = (listSize + 1) / 2;
sL->size = listSize;
half2->size = listSize-1;
}
ListNode* front = sL->head;
for (int i = 1; i < listSize; i++)
front = front->next;
//Start 2 half
half2->head = front->next;
//Cut main list
front->next = NULL;
//Set tails
half2->tail = sL->tail;
sL->tail = front;
}
//Merge two list of States sorted in increasing order into one list which is in increasing order || Comparing _t value
ListNode* sortedMerge_State(ListNode* a, ListNode* b)
{
ListNode* result = NULL;
//BASE CASE
if (a == NULL)
return(b);
if (b == NULL)
return(a);
State* state1 = (State*)a->data;
State* state2 = (State*)b->data;
//Sort current value
if (state1->_t <= state2->_t)
{
result = a;
result->next = sortedMerge_State(a->next, b);
}
else
{
result = b;
result->next = sortedMerge_State(a, b->next);
}
return result;
}//Merge two list of States sorted in increasing order into one list which is in increasing order
//Merge two list of Tasks sorted in decreasing order into one list which is in decreasing order || Comparing _lat value
ListNode* sortedMerge_Task(ListNode* a, ListNode* b)
{
ListNode* result = NULL;
if (a == NULL)
return(b);
if (b == NULL)
return(a);
Task* task1 = (Task*)a->data;
Task* task2 = (Task*)b->data;
if (task1->_lat >= task2->_lat)
{
result = a;
result->next = sortedMerge_Task(a->next, b);
}
else
{
result = b;
result->next = sortedMerge_Task(a, b->next);
}
return result;
}
//Sort a list of States by increasing order || Comparing _t value
void fusionSort_State(List* sL) {
ListNode* head = sL->head;
List* half2 = consList();
if (head == NULL || head->next == NULL) return;
//Cut list in two half
splitList(sL, half2);
//Recursiv call || Sort the two half
fusionSort_State(sL);
fusionSort_State(half2);
//Merge and sort the sorted halfs
sL->head = sortedMerge_State(sL->head,half2->head);
sL->size = sL->size + half2->size;
for (head = sL->head; head->next != NULL; head = head->next);
sL->tail = head;
}
//Sort a list of Tasks by decreasing order || Comparing _lat value
void fusionSort_Task(List* sL) {
ListNode* head = sL->head;
List* half2 = consList();
if (head == NULL || head->next == NULL) return;
splitList(sL, half2);
fusionSort_Task(sL);
fusionSort_Task(half2);
sL->head = sortedMerge_Task(sL->head,half2->head);
sL->size = sL->size + half2->size;
for (head = sL->head; head->next != NULL; head = head->next);
sL->tail = head;
}
//Removes multiple occurence t
List* removeMultOcc(List* sL) {
if (sL == NULL) return NULL;
if (sL->head == NULL) return NULL;
if (sL->size == 1) return sL;
fusionSort_State(sL);
ListNode* curr = sL->head;
State* state1 = NULL;
State* state2 = NULL;
//SIMILAR t
while (curr != NULL && curr->next != NULL) {
state1 = (State*)curr->data;
state2 = (State*)curr->next->data;
//Current and following element considered as duplicate
if (state1->_t == state2->_t) {
//Remove bad duplicate
if (state1->_eOe <= state2->_eOe)
removeData(state2, sL);
else
removeData(state1, sL);
}
//Next duplicate group
else curr = curr->next;
}
return sL;
}
//Summ of _dur
double sumDurTaskList(ListNode* tL) {
if (tL == NULL) return NULL;
Task* task = (Task*)tL->data;
if (tL->next == NULL) return task->_dur;
return task->_dur + sumDurTaskList(tL->next);
}
//Describe a list of state
std::string listToString_State(List* sL) {
if (sL == NULL) return "List : [ NOT INITIALIZED ].\n";
if (sL->size == 0) return "List : [ EMPTY ].\n";
if (sL->size == 1) return "START OF LIST OF STATE : [ " + stateToString((State*)sL->head->data) + " ]. END OF LIST OF STATE\n";
ListNode* curr = sL->head;
std::string st = "START OF LIST OF STATE : [\n ";
while (curr != NULL) {
st += stateToString((State*)curr->data);
if (curr->next != NULL) st += "\n \n";
curr = curr->next;
}
return st + " \n]. END OF LIST OF STATE \n \n \n";
}
//Describe a list of task
std::string listToString_Task(List* tL) {
if (tL == NULL) return "List : [ NOT INITIALIZED ].\n";
if (tL->size == 0) return "List : [ EMPTY ].\n";
if (tL->size == 1) return "START OF LIST OF TASK : [ " + taskToString((Task*)tL->head->data) + " ]. END OF LIST OF TASK\n";
ListNode* curr = tL->head;
std::string st = "START OF LIST OF TASK : [ \n";
while (curr != NULL) {
st += taskToString((Task*)curr->data);
if (curr->next != NULL) st += "\n";
curr = curr->next;
}
return st + "\n]. END OF LIST OF TASK\n \n \n";
}
//Describe a list of taskpair
std::string listToString_TaskPair(List* tL) {
if (tL == NULL) return "List : [ NOT INITIALIZED ].\n";
if (tL->size == 0) return "List : [ EMPTY ].\n";
if (tL->size == 1) return "START OF LIST OF TASKPAIR : [ " + taskPairToString((TaskPair*)tL->head->data) + " ]. END OF LIST OF TASKPAIR\n";
ListNode* curr = tL->head;
std::string st = "START OF LIST OF TASKPAIR : [ \n";
while (curr != NULL) {
st += taskPairToString((TaskPair*)curr->data);
if (curr->next != NULL) st += "\n";
curr = curr->next;
}
return st + "\n]. END OF LIST OF TASKPAIR\n \n \n";
}
// -----------------------------------------------------//
// ------------------ FPTAS TOOLS ------------------//
// -----------------------------------------------------//
//All Task on machine 2, Tasks sorted by decreasing order of latency
State* heuristic(List* l) {
//Copy list to not modify original instance
List* copyL = consList();
newCopy(l->head, copyL);
//Sort by decreasing order
fusionSort_Task(copyL);
ListNode* curr = copyL->head;
Task* currT = (Task*)curr->data;
//Heuristic's result
State* H = consState();
double temp_t = 0;
double temp_q = 0;
//Placed Task total duration
double Ak = 0;
//Heuristic
while (curr != NULL) {
temp_t = Ak / 2 + (currT->_dur / 2);
temp_q = fmax(temp_t + currT->_lat, H->_eOe);
H->_eOe = temp_q;
append(currT, H->_task2);
Ak += currT->_dur;
curr = curr->next;
}
return H;
}
//Return the delta value for duration
double findDeltaD(List* l, double sigma) { return (sigma*sumDurTaskList(l->head)) / (4 * l->size); }
//Return the delta value for latency
double findDeltaL(List* l, double sigma) {
List* copyL = consList();
newCopy(l->head, copyL);
return (sigma*heuristic(copyL)->_eOe) / (6 * l->size);
}
//Round duration depending on deltaD and latency depending on deltaL || Create a new list
List* rounding(List* taskList, double deltaD, double deltaL) {
//Current node
ListNode* curr = taskList->head;
//Current task
Task* currT = NULL;
//Rounded task
Task* newT = NULL;
//Rounded task list
List* l = consList();
if (taskList->size == 1) {
currT = (Task*)curr->data;
newT = consTask(std::ceil(currT->_dur / deltaD) * deltaD, std::ceil(currT->_lat / deltaL) * deltaL);
push(newT, l);
return l;
}
while (curr != NULL) {
currT = (Task*)curr->data;
newT = consTask(std::ceil(currT->_dur / deltaD) * deltaD, std::ceil(currT->_lat / deltaL) * deltaL);
append(newT, l);
curr = curr->next;
}
return l;
}
//Create a new list pairing the corresponding original and rounded Tasks
List* createListTaskPair(List* origin, List* rounded) {
//Paired list
List* pairL = consList();
ListNode* currO = origin->head;
ListNode* currR = rounded->head;
TaskPair* pair = NULL;
while (currO != NULL) {
//Create pair
pair = consTaskPair((Task*)currO->data, (Task*)currR->data);
//Add pair
append(pair, pairL);
//Next value
currO = currO->next;
currR = currR->next;
}
return pairL;
}
//Transpose Optimal Solution of a rounded instance to it's original instance
State* transpose(State* opt, List* taskPair){
//Transposed State || result
State* trueOpt = consState();
ListNode* currStateTask1 = opt->_task1->head;
ListNode* currStateTask2 = opt->_task2->head;
ListNode* currPair = taskPair->head;
//Placed Task total duration
double Ak = 0;
//Transpose Machine 1 Task
while (currStateTask1 != NULL) {
//Current Task
Task* currT = (Task*)currStateTask1->data;
bool found = false;
TaskPair* currP = NULL;
//Search in Pairs
while (!found) {
currP = (TaskPair*)currPair->data;
if (currT == currP->_rounded) found = true;
else currPair = currPair->next;
}
//Add Task to transposed State
append(currP->_origin, trueOpt->_task1);
//Add Task duration to _t
trueOpt->_t += currP->_origin->_dur;
//Define new _eOe
trueOpt->_eOe = fmax(trueOpt->_t + currP->_origin->_lat , trueOpt->_eOe);
//Remove Task to speed up next research
removeData(currP, taskPair);
//Reinitialize to head
currPair = taskPair->head;
//Next Task to transpose
currStateTask1 = currStateTask1->next;
}
//Only Machine 1 execution
Ak = trueOpt->_t;
//Transpose Machine 2 Task
while (currStateTask2 != NULL) {
//Current Task
Task* currT = (Task*)currStateTask2->data;
bool found = false;
TaskPair* currP = NULL;
//Search in Pairs
while (!found) {
currP = (TaskPair*)currPair->data;
if (currT == currP->_rounded) found = true;
else currPair = currPair->next;
}
//Add Task to transposed State
append(currP->_origin, trueOpt->_task2);
//Define new _eOe
trueOpt->_eOe = fmax((Ak - trueOpt->_t)/2 + currP->_origin->_dur/2 + currP->_origin->_lat, trueOpt->_eOe);
//Add curr Task time to Ak
Ak += currP->_origin->_dur;
//Remove Task to speed up next research
removeData(currP, taskPair);
//Reinitialize to head
currPair = taskPair->head;
//Next Task to transpose
currStateTask2 = currStateTask2->next;
}
return trueOpt;
}
// -----------------------------------------------------//
// ------------------ PROG DYN ALGO ------------------//
// -----------------------------------------------------//
//Use Dynamic Programmation based on States to find an Optimal Solution
State* progDynState(List* taskList) {
std::cout << "PROG DYN | State ==>> \n";
std::cout << "Task List :: \n" << listToString_Task(taskList) << "\n";
//Get-through list
ListNode * currT = taskList->head;
//Start state, (0 , 0 , 0 , 0)
State* start = consState();
//State list
List* sL = consList(); //Xi-1
push(start, sL);
List* sL2 = consList();//Xi
//Get through list
ListNode* currS = sL->head;
//Placed Task total duration
double Ak = 0;
while (currT != NULL) {
Task* ctask = (Task*)currT->data;
empty(sL2);
//Create new States with new Task and old States
while (currS != NULL) {
State* cstate = (State*)currS->data;
//std::cout << "MM |||| MM - Mother State : " << stateToString(cstate) << "\n\n";
//ON MACHINE 1
//new start, start of state + task duration
double temp_t = cstate->_t + ctask->_dur;
//max between (start of state + latency of task) and (end of original state)
double temp_q = fmax(temp_t + ctask->_lat, cstate->_eOe);
State * s1 = consState(temp_q, temp_t);
//Keep track of tasks on first machine
newCopy(cstate->_task1->head, s1->_task1);
append(currT->data, s1->_task1);
//Keep track of tasks on second machine
newCopy(cstate->_task2->head, s1->_task2);
//std::cout << "S1 |||| S1 - State 1 : " << stateToString(s1) << "\n\n";
//Add state to list
push(s1, sL2);
//ON MACHINE 2
//new start, start of state + task duration
temp_t = (Ak - cstate->_t) / 2 + (ctask->_dur / 2);
//max between (start of state + latency of task) and (end of original state)
temp_q = fmax(temp_t + ctask->_lat, cstate->_eOe);
State * s2 = consState(temp_q, cstate->_t);
//Keep track of tasks on second machine
newCopy(cstate->_task2->head, s2->_task2);
append(currT->data, s2->_task2);
//Keep track of tasks on first machine
newCopy(cstate->_task1->head, s2->_task1);
//std::cout << "S2 |||| S2 - State 2 : " << stateToString(s2) << "\n\n";
//Add state to list
push(s2, sL2);
//Next list member
currS = currS->next;
}
//Xi CREATED
//ERASE OLD SET OF STATE --- Xi-1
freeNodes(sL);
//SET IT ANEW --- Xi-1 = Xi
assignTo(sL, sL2);
//OPTIMIZATION
//Removes multiple occurence of t value, only keeping the best of each.
sL = removeMultOcc(sL);
//Keeps best state
//sL = keepBestState(sL);
currS = sL->head;
//END OF OPTIMIZATION
//Add curr Task time to Ak
Ak += ctask->_dur;
//Next list member
currT = currT->next;
}
//std::cout << "Best States : \n" << listToString_State(sL) << " \n\n";
sL = keepBestState(sL);
std::cout << "Optimal Solution : \n" << stateToString((State*)sL->head->data) << " \n";
return (State*)sL->head->data;
}
#endif // !TOOLS
What is wrong with my code ?
It seems like something is bad in my memory management but I can't find where. I thank you greatly for your help !
I'm using Visual Studio 2019.

exc bad access C

I am making a simple BST and, in the add_to_bst() function, it is throwing an error in the first line when referencing the object's value.
CODE
typedef struct node {
int value;
struct node* leftChild;
struct node* rightChild;
} BSTNode;
BSTNode *new_BSTNode(int val) {
BSTNode *this = (BSTNode *) malloc(sizeof(BSTNode));
this->value = val;
this->leftChild = (BSTNode * ) malloc(sizeof(BSTNode));
this->rightChild = (BSTNode * ) malloc(sizeof(BSTNode));
this->leftChild = NULL;
this->rightChild = NULL;
return this;
}
typedef struct bst {
BSTNode * root;
} BST;
BST *new_BST(int root_val) {
BST *this = (BST *) malloc(sizeof(BST));
this->root = (BST * ) malloc(sizeof(BSTNode));
this->root->value = root_val;
// this->root->value = (int *) malloc(sizeof(int));
return this;
}
int node_get(BSTNode *n, int i) {
if (n == NULL) return -1;
if (i == n-> value) return 1;
if (i > n-> value) return node_get(n->rightChild, i);
else return node_get(n->leftChild, i);
}
int bst_get(BST *bst, int i) {
return node_get(bst->root, i);
}
void add_to_bst_node(int i, BSTNode *to) {
int n = to->value; // <--- ERR
printf("\nBST VAL: %d", n);
if (i > n) {
if (to->rightChild == NULL)
to->rightChild = new_BSTNode(i);
else
add_to_bst_node(i, to->rightChild);
} else {
if (to->leftChild == NULL)
to->leftChild = new_BSTNode(i);
else
add_to_bst_node(i, to->leftChild);
}
}
void add_to_bst(BST *tree, int i) {
if (tree->root != NULL) {
add_to_bst_node(i, tree->root);
} else {
tree->root = new_BSTNode(i);
}
}
int main() {
BST *bst = new_BST(10);
add_to_bst(bst, 10);
}
RUN MSG:
0x7fa64fc00690
0x7fa64fc00640
First Val: 10
Process finished with exit code 11
BUILD ERR:
BSTNode *new_BSTNode(int val) {
BSTNode *this = (BSTNode *) malloc(sizeof(BSTNode));
this -> value = val;
this -> leftChild = (BSTNode * ) malloc(sizeof(BSTNode));
this -> leftChild = (BSTNode * ) malloc(sizeof(BSTNode));
return this;
}
This leaves this->rightChild uninitialized and leaves this->leftChild pointing to uninitialized garbage. Neither of these issues is fixed in the code that calls new_BSTnode.
void add_to_bst_node(int i, BSTNode *to) {
int n = to -> value; // <------ ERROR
Not surprising, since to comes from leftChild and rightChild, both of which are broken by the logic of new_BSTNode.
Also:
BST *new_BST(int root_val) {
BST *this = (BST *) malloc(sizeof(BST));
this -> root = (BST * ) malloc(sizeof(BSTNode));
this -> root -> value = root_val;
// this -> root -> value = (int *) malloc(sizeof(int));
return this;
}
This doesn't set this->root->leftChild or this->root->rightChild either, so again, they're garbage that gets passed to add_to_bst_node as to.
The creation of the new node, and insertion into the tree seems incorrect.
A new node should not allocate space for the left and right subtrees. Since new nodes are always added to the extremities, they never have subtrees when new anyway.
BSTNode *new_BSTNode( int val )
{
BSTNode *this = ( BSTNode * ) malloc( sizeof( BSTNode ) );
if ( this != NULL )
{
this->value = val;
this->leftChild = NULL;
this->rightChild = NULL;
}
return this;
}
Using a recursive algorithm when inserting new data allows the code to "walk" the tree, finding the correct place for insertion.
void add_to_bst_node( int value, BSTNode *to )
{
if (to != NULL)
{
if (value > to->value)
{
// Add to child-right subtree
if (to->rightChild == NULL)
{
// right-tree is empty, create it
to->rightChild = new_BSTNode( value );
}
else
{
// add it somewhere on the right-side (recursively)
add_to_bst_node( value, to->rightChild );
}
}
else // if (i <= to->value)
{
// Add to child-left subtree
if (to->leftChild == NULL)
{
// left-tree is empty, create it
to->leftChild = new_BSTNode( value );
}
else
{
// add it somewhere on the right-side (recursively)
add_to_bst_node( value, to->leftChild );
}
}
}
}
A tree is just a node. Making a separate structure for a "tree" is just extra work.
typedef BSTNode BST;
So the creation of a tree, is just the creation of a node:
BST *new_BST( int value )
{
return new_BSTNode( value );
}
The branch in add_to_BST() always chooses the tree->root != NULL if it was initialised error-free. Then the add_to_BST_node() dereferences garbage, (as the other answers have pointed out); here is a graphical representation of the memory allocating functions,
And,
I recommend thinking about what the states are in ones system and drawing them out first so one doesn't fall into an invalid state. Also, if one is doing a constructor, it's a good idea to initialise the entire structure.

AVL tree delete Item in C

As I try to delete some items from my AVL tree, I'm losing as result some other items. You can see this from the example in the picture.
What is wrong with my code?
#include <stdio.h>
#include <stdlib.h>
typedef struct Tree{
int key;
struct Tree *left,*right;
int height;
}tree;
int height(tree *t)
{
if (t == NULL)
return 0;
return t->height;
}
int getBalance(tree *t)
{
if(t==NULL)
return 0;
return height(t->left)-height(t->right);
}
int max(int a, int b)
{
return (a > b)? a : b;
}
tree* newNode(int key)
{
tree* node = (tree*)malloc(sizeof(tree));
node->key = key;
node->left = NULL;
node->right = NULL;
node->height = 1; // new node is initially added at leaf
return(node);
}
tree* insert(tree* node, int key)
{
/* 1. Perform the normal BST rotation */
if (node == NULL)
return(newNode(key));
if (key < node->key)
node->left = insert(node->left, key);
else
node->right = insert(node->right, key);
/* 2. Update height of this ancestor node */
node->height = max(height(node->left), height(node->right)) + 1;
return node;
}
void print_preorder(tree * tTree)
{
if(tTree)
{
printf("%d ",tTree->key);
print_preorder(tTree->left);
print_preorder(tTree->right);
}
}
void deleteTree(tree * tTree)
{
if (tTree)
{
deleteTree(tTree->left);
deleteTree(tTree->right);
free(tTree);
}
}
tree* minItem(tree *tTree) /* delete */
{
if(tTree->left)
{
tTree = tTree->left;
}
else;
return tTree;
}
tree* del(tree *tTree, int delItem) /* delete( main body) */
{
if(!(tTree))
return tTree;
if(delItem < tTree->key)
tTree->left = del(tTree->left, delItem);
else
if(delItem > tTree->key)
tTree->right = del(tTree->right, delItem);
else
if((tTree->left) && (tTree->right))
{
tree *tmp=minItem(tTree->right);
tTree->key = tmp->key;
if(tTree->right->left)
tTree->right = del(tTree->right,tTree->right->left->key);
else tTree->right = del(tTree->right,tTree->right->key);
}
else
if(tTree->left)
tTree = tTree->left;
else
tTree = tTree->right;
return tTree;
}
tree* rotateLeft(tree* t)
{
tree *y = t->right;
tree *T2 = y->left;
// Perform rotation
y->left = t;
t->right = T2;
// Update heights
t->height = max(height(t->left), height(t->right))+1;
y->height = max(height(y->left), height(y->right))+1;
// Return new root
return y;
}
tree* rotateRight(tree* t)
{
tree *x = t->left;
tree *T2 = x->right;
// Perform rotation
x->right = t;
t->left = T2;
// Update heights
t->height = max(height(t->left), height(t->right))+1;
x->height = max(height(x->left), height(x->right))+1;
// Return new root
return x;
}
tree *balanceNode(tree *t)
{
if (!t) return t;
int balance = getBalance(t);
if (balance > 1 && getBalance(t->left) >= 0) /* rotateReight */
return rotateRight(t);
if (balance < -1 && getBalance(t->right) <= 0) /* rotateLeft */
return rotateLeft(t);
if (balance > 1 && getBalance(t->left) < 0) /* rotateLeftReight */
{
t->left = rotateLeft(t->left);
return rotateRight(t);
}
if (balance < -1 && getBalance(t->right) > 0) /* rotateReightLeft */
{
t->right = rotateRight(t->right);
return rotateLeft(t);
}
return t;
}
int main()
{
tree *Tree, *delTree;
Tree = NULL; delTree = NULL;
int i, a[]={7,3,9,10,8,1,4,2,6,5};
for(i=0;i<10;i++) /* construct tree */
Tree = insert(Tree,a[i]);
/* Printing nodes of tree */
printf("Pre Order Display\n");
print_preorder(Tree);
printf("\nBalanced Tree\n");
Tree=balanceNode(Tree);
print_preorder(Tree);
while(1)
{
printf("\nEnter an Item that You Want to Delete: ");
scanf("%d",&i);
printf("\n");
delTree = del(Tree,i);
delTree = balanceNode(delTree);
/* Pre-order displays root node, left node and then right node. */
print_preorder(delTree);
}
printf("\n");
deleteTree(Tree);
deleteTree(delTree);
printf("\n");
return 0;
}
It would probably be best if you figure it out yourself. The print_preorder function could be useful for debugging your code.
The tricky part of the deletion is this code, so you could trace what's happpening there:
if((tTree->left) && (tTree->right))
{
tree *tmp=minItem(tTree->right);
tTree->key = tmp->key;
if(tTree->right->left)
tTree->right = del(tTree->right,tTree->right->left->key);
else tTree->right = del(tTree->right,tTree->right->key);
}
This version seems to work:
#include <stdio.h>
#include <stdlib.h>
typedef struct Tree{
int key;
struct Tree *left,*right;
int height;
}tree;
int height(tree *t)
{
if (t == NULL)
return 0;
return t->height;
}
int getBalance(tree *t)
{
if(t==NULL)
return 0;
return height(t->left)-height(t->right);
}
int max(int a, int b)
{
return (a > b)? a : b;
}
tree* newNode(int key)
{
tree* node = (tree*)malloc(sizeof(tree));
node->key = key;
node->left = NULL;
node->right = NULL;
node->height = 1; // new node is initially added at leaf
return(node);
}
tree* insert(tree* node, int key)
{
/* 1. Perform the normal BST rotation */
if (node == NULL)
return(newNode(key));
if (key < node->key)
node->left = insert(node->left, key);
else
node->right = insert(node->right, key);
/* 2. Update height of this ancestor node */
node->height = max(height(node->left), height(node->right)) + 1;
return node;
}
void print_preorder(tree * tTree)
{
if(tTree)
{
printf("%d ",tTree->key);
print_preorder(tTree->left);
print_preorder(tTree->right);
}
}
void deleteTree(tree * tTree)
{
if (tTree)
{
deleteTree(tTree->left);
deleteTree(tTree->right);
free(tTree);
}
}
tree* del(tree *tTree, int delItem) /* delete( main body) */
{
if(!(tTree))
return tTree;
if(delItem < tTree->key)
tTree->left = del(tTree->left, delItem);
else
if(delItem > tTree->key)
tTree->right = del(tTree->right, delItem);
else
{
tree *oTree = tTree;
if((tTree->left) && (tTree->right))
{
tree *parent = tTree->right;
tTree = parent->left;
if (tTree)
{
while(tTree->left)
{
parent = tTree;
tTree = tTree->left;
}
parent->left = tTree->right;
tTree->right = oTree->right;
}
else
tTree = parent;
tTree->left = oTree->left;
}
else
if(tTree->left)
tTree = tTree->left;
else
tTree = tTree->right;
free(oTree);
}
return tTree;
}
tree* rotateLeft(tree* t)
{
tree *y = t->right;
tree *T2 = y->left;
// Perform rotation
y->left = t;
t->right = T2;
// Update heights
t->height = max(height(t->left), height(t->right))+1;
y->height = max(height(y->left), height(y->right))+1;
// Return new root
return y;
}
tree* rotateRight(tree* t)
{
tree *x = t->left;
tree *T2 = x->right;
// Perform rotation
x->right = t;
t->left = T2;
// Update heights
t->height = max(height(t->left), height(t->right))+1;
x->height = max(height(x->left), height(x->right))+1;
// Return new root
return x;
}
tree *balanceNode(tree *t)
{
if (!t) return t;
int balance = getBalance(t);
if (balance > 1 && getBalance(t->left) >= 0) /* rotateReight */
return rotateRight(t);
if (balance < -1 && getBalance(t->right) <= 0) /* rotateLeft */
return rotateLeft(t);
if (balance > 1 && getBalance(t->left) < 0) /* rotateLeftReight */
{
t->left = rotateLeft(t->left);
return rotateRight(t);
}
if (balance < -1 && getBalance(t->right) > 0) /* rotateReightLeft */
{
t->right = rotateRight(t->right);
return rotateLeft(t);
}
return t;
}
int main(void)
{
tree *Tree;
Tree = NULL;
int i, a[]={7,3,9,10,8,1,4,2,6,5};
for(i=0;i<10;i++) /* construct tree */
Tree = insert(Tree,a[i]);
/* Printing nodes of tree */
printf("Pre Order Display\n");
print_preorder(Tree);
printf("\nBalanced Tree\n");
Tree=balanceNode(Tree);
print_preorder(Tree);
while(1)
{
printf("\nEnter an Item that You Want to Delete: ");
scanf("%d",&i);
printf("\n");
Tree = del(Tree,i);
printf("After Delete\n");
/* Pre-order displays root node, left node and then right node. */
print_preorder(Tree);
Tree = balanceNode(Tree);
printf("\nAfter Balance\n");
print_preorder(Tree);
}
printf("\n");
deleteTree(Tree);
printf("\n");
return 0;
}
yeah! I've used a new variable "delTree" to delete a node from my tree, but if I use the same "Tree" instead of "delTree" it will be OK, what I needed
do
{
printf("\nEnter an Item that You Want to Delete: ");
scanf("%d",&i);
printf("\n");
Tree = del(Tree,i);
Tree = balanceNode(Tree);
print_preorder(Tree);
i--;
}while(i);
Thanks to all!

adding nodes to a binary search tree randomly deletes nodes

stack. I've got a binary tree of type TYPE (TYPE is a typedef of data*) that can add and remove elements. However for some reason certain values added will overwrite previous elements. Here's my code with examples of it inserting without overwriting elements and it not overwriting elements.
the data I'm storing:
struct data {
int number;
char *name;
};
typedef struct data data;
# ifndef TYPE
# define TYPE data*
# define TYPE_SIZE sizeof(data*)
# endif
The tree struct:
struct Node {
TYPE val;
struct Node *left;
struct Node *rght;
};
struct BSTree {
struct Node *root;
int cnt;
};
The comparator for the data.
int compare(TYPE left, TYPE right) {
int left_len; int right_len; int shortest_string;
/* find longest string */
left_len = strlen(left->name);
right_len = strlen(right->name);
if(right_len < left_len) { shortest_string = right_len; } else { shortest_string = left_len; }
/* compare strings */
if(strncmp(left->name, right->name, shortest_string) > 1) {
return 1;
}
else if(strncmp(left->name, right->name, shortest_string) < 1) {
return -1;
}
else {
/* strings are equal */
if(left->number > right->number) {
return 1;
}
else if(left->number < right->number) {
return -1;
}
else {
return 0;
}
}
}
And the add method
struct Node* _addNode(struct Node* cur, TYPE val) {
if(cur == NULL) {
/* no root has been made */
cur = _createNode(val);
return cur;
}
else {
int cmp;
cmp = compare(cur->val, val);
if(cmp == -1) {
/* go left */
if(cur->left == NULL) {
printf("adding on left node val %d\n", cur->val->number);
cur->left = _createNode(val);
}
else {
return _addNode(cur->left, val);
}
}
else if(cmp >= 0) {
/* go right */
if(cur->rght == NULL) {
printf("adding on right node val %d\n", cur->val->number);
cur->rght = _createNode(val);
}
else {
return _addNode(cur->rght, val);
}
}
return cur;
}
}
void addBSTree(struct BSTree *tree, TYPE val)
{
tree->root = _addNode(tree->root, val);
tree->cnt++;
}
The method to create a new node:
struct Node* _createNode(TYPE val) {
struct Node* new_node;
new_node = (struct Node*)malloc(sizeof(struct Node*));
new_node->val = val;
new_node->left = NULL;
new_node->rght = NULL;
return new_node;
}
The function to print the tree:
void printTree(struct Node *cur) {
if (cur == 0) {
printf("\n");
}
else {
printf("(");
printTree(cur->left);
printf(" %s, %d ", cur->val->name, cur->val->number);
printTree(cur->rght);
printf(")\n");
}
}
Here's an example of some data that will overwrite previous elements:
struct BSTree myTree;
struct data myData1, myData2, myData3;
myData1.number = 5;
myData1.name = "rooty";
myData2.number = 1;
myData2.name = "lefty";
myData3.number = 10;
myData3.name = "righty";
initBSTree(&myTree);
addBSTree(&myTree, &myData1);
addBSTree(&myTree, &myData2);
addBSTree(&myTree, &myData3);
printTree(myTree.root);
Which will print:
((
righty, 10
)
lefty, 1
)
Finally here's some test data that will go in the exact same spot as the previous data, but this time no data is overwritten:
struct BSTree myTree;
struct data myData1, myData2, myData3;
myData1.number = 5;
myData1.name = "i";
myData2.number = 5;
myData2.name = "h";
myData3.number = 5;
myData3.name = "j";
initBSTree(&myTree);
addBSTree(&myTree, &myData1);
addBSTree(&myTree, &myData2);
addBSTree(&myTree, &myData3);
printTree(myTree.root);
Which prints:
((
j, 5
)
i, 5 (
h, 5
)
)
Does anyone know what might be going wrong? Sorry if this post was kind of long.
it looks like there is an error in your _addNode procedure. It looks like you arent properly storing the new node references in the tree.
struct Node* _addNode(struct Node* cur, TYPE val) {
if(cur == NULL) {
/* no root has been made */
cur = _createNode(val);
return cur;
}
else {
int cmp;
cmp = compare(cur->val, val);
if(cmp == -1) {
/* go left */
cur->left = _addNode(cur->left, val);
}
else if(cmp >= 0) {
/* go right */
cur->left = _addNode(cur->right, val);
}
return cur;
}
the _addnode function was kind of confusing because you were using the return value inconsistently. i believe this version should avoid loosing any nodes.
I don't see an obvious flaw. I would suggest reworking the tree to hold int's or something simpler than your current data. If the tree works fine then at least you know where to look and not worry about the generic tree code.
I suspect _createNode(), can you add that code?

Resources