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;
}
Related
I am trying the implement a function which checks whether two binary search trees are equal, order of the nodes not matter. But my implementation does not work.
I am not allowed to flatten the trees into arrays.
this is what I have so far:
int isIdentical(struct Node* root1, struct Node* root2)
{
if (root1 == NULL && root2 == NULL)
return 1;
else if (root1 == NULL || root2 == NULL)
return 0;
else {
if (root1->data == root2->data && isIdentical(root1->left, root2->left)
&& isIdentical(root1->right, root2->right))
return 1;
else
return 0;
}
}
when supplied with trees containing the nodes tree A = 2 4 5 6 and Tree B = 2 5 4 6, the output should be:
1, meaning they are equal, but instead I am getting 0. I am not sure where I am going wrong.
This is how Node is implemeted:
struct Node {
int data;
struct Node* left;
struct Node* right;
};
Make a recursive function that traverses treeA and checks that every item is present in treeB. On failure it abandons the search and returns 0 for failure. It can be your function
int isIdentical(struct Node* root1, struct Node* root2)
If success, call the function again with the arguments for treeA and treeB reversed. The 'check if present' operation can be iterative and inline, because it does not need to backtrack.
Example untried code, to give the idea.
int isAllFound(struct Node* root1, struct Node* root2)
{
// recursive parse of tree 1
if (root1 == NULL)
return 1;
// iterative search of tree 2
int found = 0;
struct Node *root = root2;
while(root != NULL) {
if(root1->data == root->data) {
found = 1;
break;
}
if(root1->data < root->data)
root = root->left;
else
root = root->right;
}
if(!found)
return 0;
// continue recursive parse of tree 1
if(!isAllFound(root1->left, root2))
return 0;
if(!isAllFound(root1->right, root2))
return 0;
return 1;
}
Then call like
if(isAllFound(treeA, treeB) && isAllFound(treeB, treeA))
puts("Success!");
If every item of treeA can be found in treeB, and every item of treeB can be found in treeA then they contain the same data. Provided the keys are unique.
Why do you think they are equal? They are not.
tree A is represented as 2 4 5 6 which I guess you obtained by some sort of pre-order or level-order traversal. If your tree B (2, 5, 4, 6) is equal then with the same sort of traversal you'd obtain same order. They are not equal if the traversal is the same.
Order of nodes doesn't matter:
If the order of the nodes doesn't matter. One thing you could do is do an inorder traversal for both trees and you get a sorted array from both. Then compare both arrays element by element and declare equal or not.
Your function will only compare as equal 2 trees that have exactly the same structure. If the trees are balanced differently, the comparison will return 0 even if the values are identical.
Performing this comparison is non trivial as the trees can have an arbitrary depth if they are not balanced.
You can walk the first tree in depth first order to populate an array and then walk the second tree in depth first order, checking that the values are identical to those in the array.
Here is a simple implementation:
#include <stdlib.h>
struct Node {
int data;
struct Node* left;
struct Node* right;
};
size_t tree_length(const struct Node *root) {
return root ? 1 + tree_length(root->left) + tree_length(root->right) : 0;
}
void tree_store(int *array, size_t *pos, struct Node *node) {
if (node) {
tree_store(array, pos, node->left);
array[++*pos - 1] = node->data;
tree_store(array, pos, node->right);
}
}
int tree_check(int *array, size_t *pos, struct Node *node) {
if (node) {
return tree_check(array, pos, node->left)
&& array[++*pos - 1] == node->data
&& tree_check(array, pos, node->right);
} else {
return 1;
}
}
/* compare trees: return 0 if different, 1 if same values, -1 if allocation error */
int isIdentical(const struct Node *root1, const struct Node *root2) {
size_t len1 = tree_length(root1);
size_t len2 = tree_length(root2);
size_t pos;
if (len1 != len2)
return 0;
if (len1 == 0)
return 1;
int *array = malloc(sizeof(*array) * len1);
if (!array)
return -1;
pos = 0;
tree_store(array, &pos, root1);
pos = 0;
int res = tree_check(array, &pos, root2);
free(array);
return res;
}
If you are not allowed to convert the trees to arrays, you could:
normalize both trees, then use your simple comparator, but this will modify the trees and is difficult.
implement a stack based iterator and iterate both trees in parallel.
Here is a simple implementation of the latter:
#include <stddef.h>
struct Node {
int data;
struct Node *left;
struct Node *right;
};
size_t max_size(size_t a, size_t b) {
return a < b ? b : a;
}
size_t tree_depth(const struct Node *root) {
return root ? 1 + max_size(tree_depth(root->left), tree_depth(root->right)) : 0;
}
int tree_next(const struct Node **stack, size_t *ppos, int *value) {
size_t pos = *ppos;
if (stack[pos] == NULL) {
if (pos == 0)
return 0; // no more values
pos--;
} else {
while (stack[pos]->left) {
stack[pos + 1] = stack[pos]->left;
pos++;
}
}
*value = stack[pos]->data;
stack[pos] = stack[pos]->right;
*ppos = pos;
return 1;
}
/* compare trees: return 0 if different, 1 if same values, -1 if allocation error */
int isIdentical(const struct Node *root1, const struct Node *root2) {
if (root1 == NULL || root2 == NULL)
return root1 == root2;
size_t depth1 = tree_depth(root1);
size_t depth2 = tree_depth(root2);
const struct Node *stack1[depth1];
const struct Node *stack2[depth2];
size_t pos1 = 0;
size_t pos2 = 0;
stack1[pos1++] = root1;
stack2[pos2++] = root2;
for (;;) {
int value1, value2;
int has1 = tree_next(stack1, &pos1, &value1);
int has2 = tree_next(stack2, &pos2, &value2);
if (!has1 && !has2)
return 1;
if (!has1 || !has2 || value1 != value2)
return 0;
}
}
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];
}
I cannot seem to get this function to work. It is supposed to find the preorder of a given binary tree, and put those integers into an array. This function was adapted from a similar print preorder traversal that can be found on geeksforgeeks.
//node struct
typedef struct node
{
// Each node holds a single integer.
int data;
// Pointers to the node's left and right children.
struct node *left, *right;
} node;
node *create_node(int data)
{
node *n = calloc(1, sizeof(node));
n->data = data;
return n;
}
unsigned int node_count_recursive(node *root)
{
unsigned int count = 1;
if (root->left != NULL)
count += node_count_recursive(root->left);
if (root->right != NULL)
count += node_count_recursive(root->right);
return count;
}
unsigned int node_count(node *root)
{
unsigned int count = 0;
if (root != NULL)
count = node_count_recursive(root);
return count;
}
// helper function that takes in the root, a dynamically allocated array, and count variable
// initialized to 0
// problem I believe is in this function
unsigned int preorder_helper(node *root, int *array, unsigned int count)
{
if (root == NULL)
return 0;
// This does not work
array[count++] = root->data;
count = preorder_helper(root->left, array, count);
count = preorder_helper(root->right, array, count);
return count;
}
// creates dynamically allocated array for helper function.
int *preorder_array(node *root)
{
int *array = malloc(sizeof(node) * node_count(root));
preorder_helper(root, array, 0);
return array;
}
// creates tree
int main(void)
{
node *root1;
int *preArray;
root1 = create_node(23);
root1->left = create_node(12);
root1->left->left = create_node(5);
root1->left->right = create_node(18);
root1->right = create_node(71);
root1->right->right = create_node(56);
// points preArray pointer to function
preArray = preorder_array(root1);
// loops through each integer in array
for (int i = 0; i < node_count(root1); i++) //node_count counts nodes in tree
printf("%d ", preArray[i]);
return 0;
}
The preorder_helper function seems to get the first 2 or 3 correct preorder values, but then the rest of the array is 0. The output of this code is this:
56 12 5 0 0 0
Any help is greatly appreciated, thanks.
I am trying to load a hash table of node*(s)-
typedef struct node{
char word[LENGTH+1];
struct node* next;
}node;
(don't worry about length, it is defined in the file that calls this)
-into memory, but this:
// make hash table
node* hashtable[729];
node* new_node = malloc(sizeof(node));
node* cursor = NULL;
int bucket;
while(sscanf(dictionary,"%s",new_node->word) != 0)
{
bucket = hash(new_node->word);
cursor = hashtable[bucket];
while(cursor->next != NULL)
{
cursor = cursor->next;
}
cursor->next = new_node;
}
return true;
keeps turning up to be a segmentation fault (specifically the condition of the while loop). I am baffled, what is going on? Thank you in advance to any who helps! I really appreciate your help!
You need to allocate memory for each node that is going into your hash table. How's about something like the following:
/* make hash table */
node* hashtable[729];
/* initialise all buckets to NULL */
memset(hashtable, 0, sizeof(node*)*729);
node new_node; /* Use a stack node for the temporary */
new_node.next = NULL;
node** cursor = NULL;
int bucket;
while(sscanf(dictionary,"%s",new_node.word) != 0)
{
bucket = hash(new_node.word);
cursor = &hashtable[bucket];
while(*cursor != NULL)
{
cursor = &(*cursor)->next;
}
if ((*cursor = malloc(sizeof(node))) != NULL)
/* Copy from temporary to hashed node. Assumes structure is 'flat' */
**cursor = new_node;
else {
/* panic! */
}
}
return true;
Edit:
I've refactored some code and produced a standalone example that compiles and runs, For simplicity, I've employed a totally bogus hash function and reduced the number of buckets to fit its output of 0-25. I've tried to split out the hashtable 'object' and started the effort to be a little more disciplined to avoid buffer overruns, etc.
For the traversal of the linked list of nodes in a bucket of the hashtable, I've included two versions--one that uses the node** (pointer to a pointer) and another that doesn't--in an attempt to demonstrate the use of the double star. Change the #if 1 to #if 0 to use the "single star" version.
I hope that, collectively, these changes help clarify (more than they obscure) the original purpose, although I apologise for the verboseness of the code that follows:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define LENGTH 64
typedef struct node {
char word[LENGTH+1];
struct node * next;
} node;
typedef struct hashtable {
node * table[26];
} hashtable;
/* The cleverest 'hashing' function in the world ever! */
int hash(const char * str) {
if (str && str[0]) return tolower(str[0]) - 'a';
return 0;
}
/* Allocate a new node and initialise it with the given word */
node * node_create(const char * word) {
node * nd = NULL;
if (word && (nd = malloc(sizeof(node)))) {
strncpy(nd->word, word, sizeof(nd->word)-1);
nd->word[sizeof(nd->word) - 1] = '\0';
nd->next = NULL;
}
return nd;
}
/* Set all the buckets' pointers to NULL */
void hashtable_init(hashtable * ht) {
if (ht) memset(ht, 0, sizeof(hashtable));
}
/* Place the given node into the hashtable, taking responsibility for it */
void hashtable_insert_node(hashtable * ht, node * nd) {
if (ht && nd) {
#if 1 /* More succint version using node** */
/* Identify the bucket this node should go into */
node ** cursor = ht->table + hash(nd->word);
/* Append this node to this bucket's list of nodes */
while (*cursor != NULL) cursor = &(*cursor)->next;
*cursor = nd;
#else /* Version that avoids use of node** */
int bucket = hash(nd->word);
/* Identify the bucket this node should go into */
if (ht->table[bucket]) {
node * cursor = ht->table[bucket];
while (cursor->next) cursor = cursor->next;
cursor->next = nd;
} else {
ht->table[bucket] = nd;
}
#endif
nd->next = NULL; // Ensure the new node is the last in the list
}
}
/* Free the contents of the given hashtable */
void hashtable_free_contents(hashtable * ht) {
if (ht) {
int i;
for (i=0; i < sizeof(ht->table)/sizeof(ht->table[0]); ++i) {
node * cursor = ht->table[i];
while (cursor != NULL) {
node * next = cursor->next;
free(cursor);
cursor = next;
}
}
}
}
/* Dump the contents of the given hashtable to stdout */
void hashtable_dump(const hashtable * ht) {
if (ht) {
int i;
for (i=0; i < sizeof(ht->table)/sizeof(ht->table[0]); ++i) {
printf("Bucket %d:", i);
node * cursor = ht->table[i];
while (cursor != NULL) {
printf(" %s", cursor->word);
cursor = cursor->next;
}
printf("\n");
}
}
}
int main(int argc, char * argv[]) {
char dictionary[] = {
"apples "
"apricots "
"oranges "
"lemons "
"bananas "
"raspberries "
"carrots "
"tomatoes "
"aubergines "
"limes "
"blueberries "
"plums "
"pears "
"peaches "
"pineapples "
"tangerines "
"kiwis "
"passion_fruit "
"strawberries "
};
hashtable ht;
hashtable_init(&ht);
char * p = dictionary; /* Pointer for traversing the dictionary */
node new_node; /* Temporary node for storing word read from dictionary */
new_node.next = NULL;
int n; /* Number of bytes read from dictionary in sscanf call */
char format[16];
/* If a huge word is in the dictionary, guard against buffer overflow */
snprintf(format, sizeof(format), "%%%ds%%n", sizeof(new_node.word));
while(sscanf(p, format, new_node.word, &n) == 1) {
/* Insert (a copy of the) new node into hashtable */
hashtable_insert_node(&ht, node_create(new_node.word));
/* Move forwards through the dictionary */
p += n;
}
hashtable_dump(&ht);
hashtable_free_contents(&ht);
return 0;
}
Just allocate memory for each node of the hashtable and then dereference them.
i.e.
int i ;
for(i = 0; i < 729; ++i) {
hashtable[i] = malloc(sizeof(node));
hashtable[i]->next = NULL ;
}
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.