Structuring leafs in a hierarchical tree - c

This code fills a tree with values based on their depths. But when traversing the tree, I cannot manage to determine the actual number of children without iterating over the parent node. This is necessary because the subleafs are stored in in the node underneath the current one. Which conceptual changes are necessary to store the leafs directly within the current node?
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef NULL
#define NULL ((void *) 0)
#endif
// ----
typedef struct _Tree_Node {
// data ptr
void *p;
// number of nodes
int cnt;
struct _Tree_Node **nodes;
// parent nodes
struct _Tree_Node *parent;
} Tree_Node;
typedef struct {
Tree_Node root;
} Tree;
void Tree_Init(Tree *this) {
this->root.p = NULL;
this->root.cnt = 0;
this->root.nodes = NULL;
this->root.parent = NULL;
}
Tree_Node* Tree_AddNode(Tree_Node *node) {
if (node->cnt == 0) {
node->nodes = malloc(sizeof(Tree_Node *));
} else {
node->nodes = realloc(
node->nodes,
(node->cnt + 1) * sizeof(Tree_Node *)
);
}
Tree_Node *res
= node->nodes[node->cnt]
= malloc(sizeof(Tree_Node));
res->p = NULL;
res->cnt = 0;
res->nodes = NULL;
res->parent = node;
node->cnt++;
return res;
}
// ----
void handleNode(Tree_Node *node, int depth) {
int j = depth;
printf("\n");
while (j--) {
printf(" ");
}
printf("depth=%d ", depth);
if (node->p == NULL) {
goto out;
}
int cnt = 0;
for (int i = 0; i < node->parent->cnt - 1; i++) {
if (node->parent->nodes[i] == node) {
cnt = node->parent->nodes[i + 1]->cnt;
}
}
printf("value=%s cnt=%i", node->p, cnt);
out:
for (int i = 0; i < node->cnt; i++) {
handleNode(node->nodes[i], depth + 1);
}
}
Tree tree;
int curdepth;
Tree_Node *curnode;
void add(int depth, char *s) {
printf("%s: depth (%d) > curdepth (%d): %d\n", s, depth, curdepth, depth > curdepth);
if (depth > curdepth) {
curnode = Tree_AddNode(curnode);
Tree_Node *node = Tree_AddNode(curnode);
node->p = malloc(strlen(s) + 1);
memcpy(node->p, s, strlen(s) + 1);
curdepth++;
} else {
while (curdepth - depth > 0) {
if (curnode->parent == NULL) {
printf("Illegal nesting\n");
return;
}
curnode = curnode->parent;
curdepth--;
}
Tree_Node *node = Tree_AddNode(curnode);
node->p = malloc(strlen(s) + 1);
memcpy(node->p, s, strlen(s) + 1);
}
}
void main(void) {
Tree_Init(&tree);
curnode = &tree.root;
curdepth = 0;
add(0, "1");
add(1, "1.1");
add(2, "1.1.1");
add(3, "1.1.1.1");
add(4, "1.1.1.1.1");
add(4, "1.1.1.1.2");
add(4, "1.1.1.1.3");
add(4, "1.1.1.1.4");
add(2, "1.1.2");
add(0, "2");
handleNode(&tree.root, 0);
}

I see two problems in you program
1) When you "realloc" the node list, you actually move in memory the node objects, so the parent pointer in their children must me updated as well. I suggest you to transform the array of nodes into an array of pointers to nodes, so you can realloc it without correcting pointers.
2) You forgot to terminate strings:
node->p = malloc(strlen(s));
memcpy(node->p, s, strlen(s));
should be:
node->p = malloc(strlen(s)+1);
memcpy(node->p, s, strlen(s)+1);
or also simply
node->p = strdup(s);
Maybe there are other issues, but I strongly suggest to correct these ones first.
I hope it may help you
Regards

If your structure is truly a tree, then the following pseudo code for recursively counting nodes may help:
def total_number_of_leaf_nodes(node):
if node does not have children:
return 1
else:
sum = 0
for each child of node:
sum += total_number_of_leaf_nodes(child)
return sum
If it is at all possible for you to use C++, then I would strongly advise it. Being able to use an std::vector or std::list to store your child nodes and being able to make the data element have a template type would greatly simplify the complexity of your code.

Related

How would you write this code in C using arrays instead

void storeBSTNodes(Node* root, vector<Node*> &nodes)
{
if (root == NULL)
return;
storeBSTNodes(root->left, nodes);
nodes.push_back(root);
storeBSTNodes(root->right, nodes);
}
How would you write this code in C (it's in C++ format currently) using an array? This is what I've got so far, but I'm confused about the part regarding nodes.push_back(root); and root->left, nodes
void storeBSTNodes(Node* root, int arr[])
{
if (root == NULL)
return;
storeBSTNodes(root->left, arr);
?
storeBSTNodes(root->right, arr);
}
Code from: https://www.geeksforgeeks.org/convert-normal-bst-balanced-bst/
The key is realloc.
But you'll soon realize that Node arr[] would have to be changed since you would need to know the existing number of elements in the array, and you would need to return the new number of elements in the array and the updated buffer pointer. Using a vector-like "class" or library would help.
Given the (untested) library below, you could use the following:
void storeBSTNodes(Node* root, Vector* nodes)
{
if (root == NULL)
return;
storeBSTNodes(root->left, nodes);
Vector_push(nodes, root); // Ignores failures.
storeBSTNodes(root->right, nodes);
}
Vector.h:
#ifndef VECTOR_H
#define VECTOR_H
#include <stdlib.h>
// A fixed-size circular buffer.
typedef struct {
size_t size;
size_t used;
void** buf;
} Vector;
// Returns NULL and sets errno on error.
// Free the vector with Vector_delete when done.
Vector* Vector_new(void);
// Returns 0 and sets errno on error.
// Destroy the vector with Vector_destroy when done.
int Vector_init(Vector* v);
// Inverse of Vector_new.
// Only call when the vector is empty.
void Vector_delete(Vector* v);
// Inverse of Vector_init.
// Only call when the vector is empty.
void Vector_destroy(Vector* v);
int Vector_is_empty(Vector* v);
// Appends an element to the vector.
// Returns 0 and sets errno on error.
int Vector_push(Vector* v, void* ele);
// Removes the last element of the vector and returns it.
// Note that this also NULL if empty.
void* Vector_pop(Vector* v);
#endif
Vector.c:
#include <assert.h>
#include <stdlib.h>
#include "Vector.h"
Vector* Vector_new(void) {
Vector v = malloc(sizeof(Vector));
if (v == NULL)
goto Error1;
if (!Vector_init(v))
goto Error2;
return v;
Error2:
free(v);
Error1:
return NULL;
}
int Vector_init(Vector* v) {
v->size = 0;
v->used = 0;
v->buf = NULL;
return 1;
}
void Vector_delete(Vector* v) {
Vector_destroy(v);
free(v);
}
void Vector_destroy(Vector* v) {
assert(v->used == 0);
free(v->buf);
}
int Vector_is_empty(Vector* v) {
return v->used == 0;
}
int Vector_push(Vector* v, void* ele) {
if (v->used == v->size) {
size_t new_size = v->size;
new_size = new_size ? new_size * 2 : 4;
void* new_buf = realloc(v->buf, new_size * sizeof(void*));
if (new_buf == NULL)
return 0;
v->size = new_size;
v->buf = new_buf;
}
v->buf[ (v->used)++ ] = ele;
return 1;
}
void* Vector_pop(Vector* v) {
if (v->used == 0)
return NULL;
return v->buf[ --(v->used) ];
}
Add other "methods" as needed.
Allocation of temporary storage would be more efficient if you could get the number of elements in the tree efficiently, for example by maintaining a counter. Failing that, a recursive function could be used to count the elements:
size_t CountBSTElements(Node *root) {
if (root)
return 1 + CountBSTElements(root->left) + CountBSTElements(root->right);
else
return 0;
}
Once the total number of elements is known, the following function can be called to allocate an array filled with an in-order traversal of the tree:
/*
* Allocates and fills array of node pointers from BST tree.
* root is the root node and n is the total number of elements in the tree.
*/
Node **GetInOrderBSTNodes(Node *root, size_t n) {
Node **nodes = malloc(n * sizeof(*nodes));
size_t front = 0;
size_t back = n;
if (!nodes)
return NULL;
while (front < back) {
if (root) {
nodes[--back] = root;
root = root->left;
} else {
root = nodes[back++];
nodes[front++] = root;
root = root->right;
}
}
return nodes;
}
Demonstration follows. The temporary storage needs to be freed once it has been used to build the balanced tree.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node Node;
struct Node {
int data;
Node *left;
Node *right;
};
/*
* Allocates and fills array of node pointers from BST tree.
* root is the root node and n is the total number of elements in the tree.
*/
Node **GetInOrderBSTNodes(Node *root, size_t n) {
Node **nodes = malloc(n * sizeof(*nodes));
size_t front = 0;
size_t back = n;
if (!nodes)
return NULL;
while (front < back) {
if (root) {
nodes[--back] = root;
root = root->left;
} else {
root = nodes[back++];
nodes[front++] = root;
root = root->right;
}
}
return nodes;
}
size_t CountBSTElements(Node *root) {
if (root)
return 1 + CountBSTElements(root->left) + CountBSTElements(root->right);
else
return 0;
}
/*
* N.B. The usage of the end index is slightly different in this version of
* buildTreeUtil() compared to the linked source:
* https://www.geeksforgeeks.org/convert-normal-bst-balanced-bst/
*
* In this version, end is one past the last index.
* I did it this way to keep the indices unsigned.
*/
/*
* Build BST from array of node pointers.
* nodes is the array of node pointers.
* start is start index in the array.
* end is one past the end index in the array.
*
* Sorry, it is recursive. :-)
*/
Node *BuildTreeUtil(Node **nodes, size_t start, size_t end)
{
Node *root;
size_t mid;
if (start >= end)
return NULL;
mid = (start + end - 1) / 2;
root = nodes[mid];
root->left = BuildTreeUtil(nodes, start, mid);
root->right = BuildTreeUtil(nodes, mid + 1, end);
return root;
}
Node *BuildTree(Node *root, size_t nelems) {
Node **nodes = GetInOrderBSTNodes(root, nelems);
if (nodes) {
/* Build BST from in-order node pointers. */
root = BuildTreeUtil(nodes, 0, nelems);
/* Free temporary storage. */
free(nodes);
} /* else leave it unbalanced */
return root;
}
/* Utility function to create a new node */
/* Borrowed from linked source. */
Node *NewNode(int data) {
Node *node = malloc(sizeof(*node));
if (node) {
node->data = data;
node->left = NULL;
node->right = NULL;
}
return (node);
}
/* Print in-order traversal of BST. */
/* Borrowed from linked source, but renamed. */
void PrintPreOrder(Node* node)
{
if (node == NULL)
return;
printf("%d ", node->data);
PrintPreOrder(node->left);
PrintPreOrder(node->right);
}
int main(void) {
Node *root;
size_t count;
/*
* Construct unbalanced BST:
*
* 4
* / \
* 3 5
* / \
* 2 6
* / \
* 1 7
*/
root = NewNode(4);
root->left = NewNode(3);
root->left->left = NewNode(2);
root->left->left->left = NewNode(1);
root->right = NewNode(5);
root->right->right = NewNode(6);
root->right->right->right = NewNode(7);
printf("Pre-order traversal of unbalanced BST is:\n");
PrintPreOrder(root);
printf("\n");
/* Get number of nodes. */
#if 0
count = 7; /* efficient :-) */
#else
count = CountBSTElements(root);
#endif
/*
* Build balanced BST:
*
* 4
* / \
* 2 6
* / \ / \
* 1 3 5 7
*/
root = BuildTree(root, count);
printf("Pre-order traversal of balanced BST is:\n");
PrintPreOrder(root);
printf("\n");
return 0;
}

convert array to binary tree with recursive strategy

I need to create a binary tree starting from vector containing some zeros where a zero represents a node that doesn't exists. for example if I got:
int a[] = {10,4,7,2,3,-1,8,9,-1,2,4,5};
I would like my output like this:
10
/ \
4 7
/ \ \
2 3 8
/ / \ /
9 2 4 5
my struct:
typedef struct node {
int n;
struct node * dx;
struct node * sx;
} *Bit_node;
method to build one node:
Bit_node bit_new(int n) {
Bit_node new_node = malloc(sizeof(struct node));
new_node -> n = n;
return new_node;
}
method to build the whole tree:
Bit_node bit_arr2tree(int a[], int size, int i) {
if (i>= size) {
return NULL;
}
if(a[i] != -1) {
Bit_node new_node = bit_new(a[i]);
new_node -> sx = bit_arr2tree(a, size, i*2 +1);
new_node -> dx = bit_arr2tree(a, size, i*2 +2);
}
return new_node;
}
But with my implementation my tree is built not considering the "holes". Is there a way to considering them , keeping the recursive strategy?
First of all, int a[] = {10,4,7,2,3,-1,8,9,-1,2,4,5}; shouldn't produce the tree you expect, with 5 as the left child of 8. Since 8 is at index 6, its left child would be at index 6 * 2 + 1 == 13. So your input should probably be int a[] = {10,4,7,2,3,-1,8,9,-1,2,4,-1,-1,5};, with two extra -1s towards the end of the array to push 5 to the correct index.
Your implementation can't work because in the pattern:
{
Bit_node new_node = malloc(...)
}
return new_node;
new_node is being accessed when not in scope. If you encounter a -1, you want to return NULL just like you're doing if you go out of bounds on the array. Returning NULL says "there is no child here", which is exactly what you want to communicate to a parent frame so that it sets the missing child to NULL.
The fix should be pretty straightforward:
Bit_node bit_arr2tree(int a[], int size, int i) {
if (i>= size || a[i] < 0) {
// ^^^^^^^^^^^
return NULL;
}
Bit_node new_node = bit_new(a[i]);
new_node->sx = bit_arr2tree(a, size, i * 2 + 1);
new_node->dx = bit_arr2tree(a, size, i * 2 + 2);
return new_node;
}
As an aside, I'd caution against typedeffing away pointers. This makes the code less readable and hides information.
Here's a runnable proof of concept:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node *left;
struct Node *right;
};
struct Node *arr2tree(int arr_len, int *arr, int i) {
if (i >= arr_len || arr[i] < 0) {
return NULL;
}
struct Node *node = malloc(sizeof(*node));
node->data = arr[i];
node->left = arr2tree(arr_len, arr, i * 2 + 1);
node->right = arr2tree(arr_len, arr, i * 2 + 2);
return node;
}
void print_tree(struct Node *root, int depth) {
if (root) {
print_tree(root->right, depth + 4);
for (int i = 0; i < depth; i++) {
printf(" ");
}
printf("%d\n", root->data);
print_tree(root->left, depth + 4);
}
}
void free_tree(struct Node *root) {
if (root) {
free_tree(root->left);
free_tree(root->right);
free(root);
}
}
int main() {
int a[] = {10,4,7,2,3,-1,8,9,-1,2,4,-1,-1,5};
struct Node *root = arr2tree(sizeof(a) / sizeof(a[0]), a, 0);
print_tree(root, 0);
free_tree(root);
return 0;
}
Output:
8
5
7
10
4
3
2
4
2
9
Given that the input data structure does not guarantee the relationship between parent and children is i*2+1 and i*2+2, a recursive solution is not really called for. The input sequence represents a breadth-first order, so it would be more natural to build the tree in breadth-first order.
As a side note: the function bit_new should also initialise the sx and dx members: you don't want to leave those with undefined values.
Here is how you could write your algorithm:
Bit_node bit_new(int n) {
Bit_node new_node = malloc(sizeof(struct node));
new_node -> n = n;
new_node -> sx = NULL;
new_node -> dx = NULL;
return new_node;
}
Bit_node bit_arr2tree(int a[], int size) {
if (size == 0) {
return NULL;
}
// Create a temporary array to store the node pointers
Bit_node nodes[size];
// Create the nodes
for (int i = 0; i < size; i++) {
nodes[i] = a[i] == -1 ? NULL : bit_new(a[i]);
}
// To link the nodes, use two indexes: parent and child
for (int child = 1, parent = 0; child < size; child += 2, parent++) {
// Here we "skip the gaps": a parent cannot be NULL:
while (nodes[parent] == NULL) {
parent++;
}
nodes[parent] -> sx = nodes[child];
if (child + 1 < size) {
nodes[parent] -> dx = nodes[child + 1];
}
}
return nodes[0];
}

AVL Tree Balancing - C

I've been trying to write up a simple AVL Tree implementation in C. It supports duplicate values as well. Everything seems to work fine but every now and then I get a poorly balanced tree. To me, the rotation functions seem to be working fine like they should. I'm thinking there is a problem with the height checks but I can't seem to find the problem.
The tree I get just from the inserts is unbalanced, so the insert is problematic. Then, before this, after deletion the tree is usually poorly balanced. It is sometimes balanced properly though, which I can't seem to identify how.
The code for this implementation is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#define SPACE_PER_NODE 2
#define MAX(x, y) (x) > (y) ? (x) : (y)
enum delete_flags {
DELETE_NO_FORCE,
DELETE_FORCE
};
typedef unsigned int uint;
struct tree_elem {
int data;
uint dup_count;
int height;
struct tree_elem* left;
struct tree_elem* right;
};
typedef struct tree_elem node;
node* create_bst();
void insert(node**, int);
void delete_elem(node**, int, uint);
node* search(node*, int);
node* get_parent(node*, node*);
node* find_min(node*);
node* get_successor(node*, node*);
uint max_depth(node*);
void display_helper(node*, int);
void display_tree(node*);
int get_height(node*);
void rotate_once_left(node**);
void rotate_once_right(node**);
void rotate_twice_left(node**);
void rotate_twice_right(node**);
void* s_malloc (const uint t) {
void* p = malloc(t);
if(!p) {
printf("Out of memory.\n");
exit(EXIT_FAILURE);
}
return p;
}
void s_free (void* p) {
if(!p) {
printf("Error: Tried to free NULL ptr.\n");
exit(EXIT_FAILURE);
}
else
free(p);
}
node* create_bst(int data) {
node* tree = (node*) s_malloc(sizeof(node));
tree->left = tree->right = NULL;
tree->data = data;
return tree;
}
void insert(node** t, int val) {
if(!(*t)) {
*t = (node*) s_malloc(sizeof(node));
(*t)->data = val;
(*t)->left = (*t)->right = NULL;
(*t)->dup_count = 0;
(*t)->height = 0;
return;
}
if((*t)->data < val) {
insert(&(*t)->right, val);
if(get_height((*t)->right) - get_height((*t)->left) >= 2) {
if((*t)->right->data < val)
rotate_once_right(&(*t));
else if((*t)->right->data > val)
rotate_twice_right(&(*t));
}
}
else if((*t)->data > val) {
insert(&(*t)->left, val);
if(get_height((*t)->left) - get_height((*t)->right) >= 2) {
if((*t)->left->data > val)
rotate_once_left(&(*t));
else if((*t)->left->data < val)
rotate_twice_left(&(*t));
}
}
else {
++(*t)->dup_count;
return; // this is important! if there are duplicates, they might cause an unwanted height change!
}
(*t)->height = MAX(get_height((*t)->left), get_height((*t)->right)) + 1;
}
node* get_successor(node* t, node* s) {
if(s->right)
return find_min(s->right);
node* suc = NULL;
node* temp = t;
// Start from root and search for successor in the tree
while (temp) {
if (s->data < temp->data) {
suc = temp;
temp = temp->left;
}
else if (s->data > temp->data)
temp = temp->right;
else
break;
}
return suc;
}
void free_tree (node* t) {
if (!t)
return;
free_tree(t->left);
free_tree(t->right);
free(t);
}
node* search(node* t, int val) {
if(!t)
return NULL;
if(t->data == val)
return t;
else if(t->data < val)
return search(t->right, val);
return search(t->left, val);
}
node* find_min(node* t) {
node* temp = t;
while(temp->left)
temp = temp->left;
return temp;
}
uint max_depth(node* t) {
if (!t)
return 0;
int ldepth = max_depth(t->left);
int rdepth = max_depth(t->right);
if (ldepth > rdepth)
return ldepth + 1;
return rdepth + 1;
}
void display_helper(node* t, int spaces) {
int width = ceil(log10(max_depth(t)+0.01)) + 2;
wchar_t* sp64 = L" ";
if (!t) {
wprintf(L"\n");
return;
}
display_helper(t->right, spaces + width);
wprintf(L"%*.*s%d\n", 0, spaces, sp64, t->data);
display_helper(t->left, spaces + width);
}
void display_tree(node* t) {
if(t)
display_helper(t, SPACE_PER_NODE);
}
int get_height(node* t) {
if(!t)
return 0;
return t->height;
}
void rotate_once_left(node** k1) {
node* temp = (*k1)->left;
(*k1)->left = temp->right;
temp->right = *k1;
(*k1)->height = MAX(get_height((*k1)->left), get_height((*k1)->right)) + 1;
temp->height = MAX(get_height(temp->left), (*k1)->height) + 1;
*k1 = temp;
}
void rotate_once_right(node** k1) {
node* temp = (*k1)->right;
(*k1)->right = temp->left;
temp->left = *k1;
(*k1)->height = MAX(get_height((*k1)->left), get_height((*k1)->right)) + 1;
temp->height = MAX(get_height(temp->right), (*k1)->height) + 1;
*k1 = temp;
}
void rotate_twice_left(node** k1) {
rotate_once_right(&(*k1)->left);
rotate_once_left(k1);
}
void rotate_twice_right(node** k1) {
rotate_once_left(&(*k1)->right);
rotate_once_right(k1);
}
int main() {
srand(time(NULL));
node* tree = create_bst(rand() % 15 + 1);
for(uint i = 0; i < 14; ++i) {
int elem;
// create unique elements from 1 to 20.
do {
elem = rand() % 15 + 1;
} while (search(tree, elem));
insert(&tree, elem);
}
display_tree(tree);
int input;
do {
printf("Enter value to delete: ");
scanf("%d", &input);
delete_elem(&tree, input, DELETE_NO_FORCE);
display_tree(tree);
} while(input != -1);
return 0;
}
One place to look is your MAX macro.
MAX(get_height((*t)->left), get_height((*t)->right)) + 1;
probably does not compute what you think it does.
In this day and age, when compilers inline with such great aplomb, you shouldn't use a macro for this computation. It's not only incorrect, it's almost certainly less efficient.
And I'll ditto here what I said in the comment: You should strongly consider test driven development. Write a predicate that checks the AVL conditions are met for a given tree, including that it's a valid BST. Now add items to an empty tree and run the predicate after each. When it reports the tree is not AVL, you'll be able to see what went wrong. When it doesn't, you'll have more confidence your code is working as intended.
Edit
Okay, expand the macro by hand (adding some whitespace):
(get_height((*t)->left)) > (get_height((*t)->right))
? (get_height((*t)->left))
: (get_height((*t)->right)) + 1;
The + 1 is affecting only the else branch. You'd need an additional set of parentheses to get the right answer.
Moreover, the heights are being computed twice. With a function, it would only happen once. Admittedly an aggressive optimizer would probably eliminate the duplicate computations, too, but that optimization is considerably more elaborate and therefore fragile than merely inlining a max() function. Why use a macro to make the compiler's job harder?

Sequence insert at arbitrary index implemented with Linked list

I'm trying to implement sequence_insert_at using the add_to_front function here
Everything before
typedef struct sequence *Sequence;
is pasted from another c file.
void sequence_insert_at(Sequence s, int pos, int item)
{
struct node* temp = s->lst;
for(; pos > 0; --pos)
{
temp = temp->rest;
}
add_to_front(&temp, item);
++s->length;
if(!temp->rest)
{
s->end = temp;
}
//s->lst = temp;
}
I don't know why I keep getting a runtime error. if I clone s->lst and traverse the clone, I'm not modifying the pointer to the node in s, but if I change temp, s->lst should have the reflected changes since the nodes are all linked still. Any ideas as to how to fix this? I tried creating another node that is one before the temp after traversal, and then setting it->rest = temp, but that failed as well.
following mistakes a could spot but only so far to get the main function run
new_sequence does not initialize anything in Sequence it creates. lst is not initialized when you access it in sequence_insert_at
struct node* temp = s->lst;
here how it should look like
Sequence new_sequence()
{
Sequence s = malloc(sizeof(struct sequence));
if(!s)
{
printf("Out of memory. Can't allocate s\n");
exit(EXIT_FAILURE);
}
s->lst = malloc(sizeof(struct node));
if(! s->lst) {
printf("Out of memory. Can't allocate lst\n");
}
s->lst->rest = NULL;
s->length = 0;
return s;
}
also s->lst->rest has to be set to NULL, this is what tells that the list has no more elements an not end witch turns obsolete.
struct sequence
{
struct node* lst;
int length;
};
You should be passing the sequence itself to your functions not a pointer to some internal data in the sequence.
add_to_front(&temp, item);
Your sequence_insert_at function should be the one that can handle any position not add_to_front() so it is easier to call with the position 0 from add_to_front() and your having the the hole work done in one function, not a half here and a half there.
void sequence_insert_at(Sequence s, int pos, int item)
{
if(s && pos <= s->length) {
print_sequence(s);
struct node *newnode = malloc(sizeof(struct node));
if (newnode == NULL) {
printf("ERROR! add_to_front ran out of memory!\n");
exit(EXIT_FAILURE);
}
newnode->first = item;
struct node* temp = s->lst;
struct node* prv = NULL;
for(int i = 0; i < pos; i++) {
printf("skip %d\n", temp->first);
prv = temp;
temp = temp->rest;
}
newnode->rest = temp;
if(pos == 0) {
printf("insert as first\n");
s->lst = newnode;
} else {
printf("insert before %d\n", temp->first);
prv->rest = newnode;
}
++s->length;
}
}
and in add_to_front only one statement is needed
void add_to_front(Sequence s, int item) {
sequence_insert_at(s, 0, item);
}
as for inserting at the back of the list
void add_to_back(Sequence s, int item) {
sequence_insert_at(s, s->length, item);
}
A small test with the main function
void print_sequence(Sequence s)
{
struct node* temp = s->lst;
for(int i = 0; i < s->length; temp = temp->rest) {
printf("%d ", temp->first);
i++;
}
printf("\n");
}
int main()
{
Sequence derp = new_sequence();
sequence_insert_at(derp, 0, 14);
add_to_front(derp, 16);
sequence_insert_at(derp, 0, 17);
sequence_insert_at(derp, 2, 15);
add_to_back(derp, 13);
print_sequence(derp);
delete_sequence(derp);
return 0;
}
output is:
17 16 15 14 13
You'll have to go trough the other functions and fix them.
Finally i should note that variable names you have choosen are little bit confusing if not misleading, i would name them this way
typedef struct node {
int data; /* the data that a node holds */
struct node* next; /* the pointer to the next node */
} Node_t;
typedef struct sequence {
struct node* head; /* head or first element of the sequence/list */
int length; /* length is ok but size is better */
} Sequence_t;

Creating a binary search tree in C99

I've got a programming class assignment due tonight at 8 PM CDT that I'm having trouble with. We are to take a list of the following numbers via reading a file:
9
30
20
40
35
22
48
36
37
38
place them in an array (easy enough), and then read these into a binary search tree using C. The first number in the list is the number of elements in the tree. The rest are placed into the following struct:
typedef struct node_struct {
int data;
struct node_struct* left;
struct node_struct* right;
} Node;
I think I've got the first part down pat. Take the stuff in using fscanf (I didn't choose to use this method, I like fgets better), call an insertion function on each member of the array, then call a "createNode" function inside the insertion function.
Problem is, I'm only getting one member into the BST. Furthermore, the BST must satisfy the condition node->left->data <= node->data < node->right->data... in other words, the nodes must be in order in the tree.
Here's what I have so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// def BST node struct
typedef struct node_struct {
int data;
struct node_struct* left;
struct node_struct* right;
} Node;
// prototypes
Node* createNode(int data);
Node* bstInsert(Node* root, int data);
// helper function prototypes
void padding(char ch, int n);
void displayTree(Node* root, int depth);
int main(int argc, char **argv)
{
FILE *in = NULL;
int num_read, count=0, array_size = 0;
if(argc != 2){
printf("hw3 <input-file>\n");
return 1;
}
in = fopen(argv[1], "r");
if(in == NULL){
printf("File can not be opened.\n");
return 2;
}
// read in the first line to get the array size
fscanf(in, "%d", &array_size);
// declare the array
int array[array_size];
// read from the second line to get each element of the array
while(!feof(in)){
fscanf(in, "%d", &num_read);
array[count] = num_read;
count++;
}
fclose(in);
if (array_size != count) {
printf("data error. Make sure the first line specifies the correct number of elements.");
return 3;
}
Node *root1 = NULL, *root2 = NULL, *root3 = NULL;
int i;
// task1: construct a bst from the unsorted array
printf("=== task1: construct a bst from the unsorted array ===\n");
for (i = 0; i < array_size; i++) {
root1 = bstInsert(root1, array[i]);
}
displayTree(root1, 0);
return 0;
}
Node* bstInsert(Node* root, int data) {
if(root == NULL){
root = createNode(data);
if(root != NULL){
root= createNode(data);
}
else{
printf("%d not inserted, no memory available.\n", data);
}
}
Node* current, previous, right;
current = root;
previous = root->left;
next = root->right;
else{
if(previous->data <= current->data){
}
}
return root;
}
Node* createNode(int data) {
// TODO
Node* aRoot;
if(!data)
return NULL;
aRoot = malloc(sizeof(Node));
if(!aRoot){
printf("Unable to allocate memory for node.\n");
return NULL;
}
aRoot->data = data;
aRoot->left = NULL;
aRoot->right = NULL;
return aRoot;
}
/* helper functions to print a bst; You just need to call displayTree when visualizing a bst */
void padding(char ch, int n)
{
int i;
for (i = 0; i < n; i++)
printf("%c%c%c%c", ch, ch ,ch, ch);
}
void displayTree(Node* root, int depth){
if (root == NULL) {
padding (' ', depth);
printf("-\n");
}
else {
displayTree(root->right, depth+1);
padding(' ', depth);
printf ( "%d\n", root->data);
displayTree(root->left, depth+1);
}
}
main, createNode, displayTree, and padding are okay, I believe. It's bstInsert where I'm having trouble. I'm just not sure how to order things to create a valid tree.
EDIT:
I've edited bstInsert and injected some more logic. It should be printing out more leaves on the tree, but alas, it's only printing out the number "30". Here's the new function.
Node* bstInsert(Node* root, int data) {
if(root == NULL){
root = createNode(data);
if(root != NULL){
root= createNode(data);
}
else{
printf("%d not inserted, no memory available.\n", data);
}
}
else{
if(data < root->data){
bstInsert(root->left, data);
}
else if(data > root->data || data == root->data){
bstInsert(root->right, data);
}
}
return root;
}
You have to assign the newly created node pointer to the correct part of the tree. This code does that. The key change is using the return value from bstInsert() correctly. The other changes are cosmetic. Note that I checked the input array by printing it out; also, it is sensible to print out the BST as you build it.
Don't use feof() as a loop control condition. It is almost invariably wrong when used as a loop control, but at least you have to also check the input operation that follows. I've written a lot of programs in my time; I've hardly ever used feof() (I found two places in my own code with it; in both, it was correctly used to distinguish between EOF and an error after an input had failed.)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// def BST node struct
typedef struct node_struct
{
int data;
struct node_struct* left;
struct node_struct* right;
} Node;
// prototypes
Node *createNode(int data);
Node *bstInsert(Node *root, int data);
// helper function prototypes
void padding(char ch, int n);
void displayTree(Node *root, int depth);
int main(int argc, char **argv)
{
FILE *in = NULL;
int num_read, count=0, array_size = 0;
if (argc != 2)
{
printf("hw3 <input-file>\n");
return 1;
}
in = fopen(argv[1], "r");
if (in == NULL)
{
printf("File can not be opened.\n");
return 2;
}
// read in the first line to get the array size
fscanf(in, "%d", &array_size);
// declare the array
int array[array_size];
// read from the second line to get each element of the array
while (count < array_size && fscanf(in, "%d", &num_read) == 1)
array[count++] = num_read;
fclose(in);
if (array_size != count)
{
printf("data error. Make sure the first line specifies the correct number of elements.");
return 3;
}
for (int i = 0; i < array_size; i++)
printf("%d: %d\n", i, array[i]);
Node *root1 = NULL;
// task1: construct a bst from the unsorted array
printf("=== task1: construct a bst from the unsorted array ===\n");
for (int i = 0; i < array_size; i++)
{
root1 = bstInsert(root1, array[i]);
displayTree(root1, 0);
}
displayTree(root1, 0);
return 0;
}
Node *bstInsert(Node *root, int data)
{
if (root == NULL)
{
root = createNode(data);
if (root == NULL)
printf("%d not inserted, no memory available.\n", data);
}
else if (data < root->data)
root->left = bstInsert(root->left, data);
else
root->right = bstInsert(root->right, data);
return root;
}
Node *createNode(int data)
{
Node *aRoot;
aRoot = malloc(sizeof(Node));
if (!aRoot)
{
printf("Unable to allocate memory for node.\n");
return NULL;
}
aRoot->data = data;
aRoot->left = NULL;
aRoot->right = NULL;
return aRoot;
}
/* helper functions to print a bst; You just need to call displayTree when visualizing a bst */
void padding(char ch, int n)
{
for (int i = 0; i < n; i++)
printf("%c%c%c%c", ch, ch, ch, ch);
}
void displayTree(Node *root, int depth)
{
if (root == NULL) {
padding (' ', depth);
printf("-\n");
}
else {
displayTree(root->right, depth+1);
padding(' ', depth);
printf ( "%d\n", root->data);
displayTree(root->left, depth+1);
}
}
Ok, think about what you want to do in the different tree configurations:
when the tree is empty -> create a root node
when the tree isn't empty -> how do the value to be inserted and the value of the root compare?
above -> insert in the right subtree
below -> insert in the left subtree
equal -> do nothing (this actually depends on how your assignment tells you to treat duplicates)
From this basic algorithm, you should be able to figure out all the corner cases.
A simplified solution (naive insertion with recursion, data input noise removed):
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
static int nums[] = { 6, 8, 4, 1, 3, 7, 14, 10, 13 }; // instead of the user input
typedef struct _node {
int value;
struct _node *left;
struct _node *right;
} node;
node *node_new(int v)
{
node *n = malloc(sizeof(*n));
assert(n);
n->value = v;
n->left = NULL;
n->right = NULL;
return n;
}
void insert(node **tree, node *leaf)
{
if (*tree == NULL) {
*tree = leaf;
} else if (leaf->value > (*tree)->value) {
insert(&((*tree)->right), leaf);
} else {
insert(&((*tree)->left), leaf);
}
}
void dump(node *tree, int level)
{
static const char *pad = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
if (tree != NULL) {
printf("%sSelf: %d\n", pad + 16 - level, tree->value);
if (tree->left) {
printf("%sLeft node:\n", pad + 16 - level);
dump(tree->left, level + 1);
}
if (tree->right) {
printf("%sRight node:\n", pad + 16 - level);
dump(tree->right, level + 1);
}
} else {
printf("%sEmpty\n", pad + 16 - level);
}
}
int main()
{
size_t n = sizeof(nums) / sizeof(*nums);
int i;
node *tree = NULL;
for (i = 0; i < n; i++) {
insert(&tree, node_new(nums[i]));
}
dump(tree, 0);
// give some work to the kernel
return 0;
}
You should consider doing this recursively. Remember that each node is a tree in itself:
#include <stdio.h>
#include <stdlib.h>
typedef struct tree_struct {
int value;
struct tree_struct* left;
struct tree_struct* right;
} Tree;
Tree* addToTree(int value, Tree* tree)
{
if (tree == NULL) {
tree = malloc(sizeof(Tree));
tree->value = value;
tree->left = NULL;
tree->right = NULL;
} else {
if (value < tree->value) {
tree->left = addToTree(value, tree->left);
} else {
tree->right = addToTree(value, tree->right);
}
}
return tree;
}
int main(int argc, char** argv)
{
Tree* tree = NULL;
int in;
while (scanf("%d", &in) != EOF) {
tree = addToTree(in, tree);
}
return 0;
}

Resources