I am trying to do a function that receives the root of a supposed BST and I want to know if the tree in question is a BST.
Problem is that, I am traveling the tree with recursion and what I'm trying to do is, put inside an array all the values of the tree. I searched for how to put a BST into an array (AddtoArray), but the answers I've found on stackoverflow and other websites didn't solve my problem. (I got seg fault).
Here's what I got so far:
#include<stdio.h>
#include<stdlib.h>
struct node{
int key;
struct node *left, *right;
};
struct node *newNode(int item){
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->key = item;
temp->left = temp->right = NULL;
return temp;
}
struct node* insert(struct node* node, int key){
if(node == NULL) return newNode(key);
if(key < node->key)
node->left = insert(node->left, key);
else if(key >= node->key)
node->right = insert(node->right, key);
return node;
}
void check(struct node *root, int *array, int i){
if(root != NULL){
check(root->left, array, i);
array[i++] = root->key;
//I tried to put i++, ++i in every place of this function (trying table test) and I realized it was too difficult to realize what to do here, I've found some functions returning an integer, the "i" in question, but they didn't work out for me.
check(root->right, array, i);
}
}
int main(){
int *array;
int array_length = sizeof(array)/sizeof(array[0]);
int i = 0;
array = (int*)malloc(array_length*sizeof(int));
struct node *root = NULL;
root = insert(root, 50);
insert(root, 30);
insert(root, 20);
insert(root, 40);
insert(root, 70);
insert(root, 60);
insert(root, 20);
check(root, array, i);
printf("PRINTING ARRAY TO SEE IF THE BST IS IN ARRAY:\n");
for(i = 0; i < array_length; i++){
printf("VALUE: %d ", array[i]);
}
free(array);
return 0;
}
I'd like to solve this problem WITHOUT using global variables. How can I do it?
I see two issues in your check-code and its usage (did not analyse the other functions):
First, your malloc does not work as intended, because sizeof(array)/sizeof(array[0]) will always give the same (small) value, probably 1 or 2, regardless of the size of your BST.
So you'd rather introduce a function getting the number of nodes and use this as the length for your array:
int array_length = getNrOfNodes(root); // function to be coded
int *array = malloc(array_length*sizeof(int));
Second, you pass an integral value i by value to a recursive function. As it is passed by value, any i++ will take effect only for the respective function call instance, but will not influence the other ones on the call stack. So it is very likely that the keys of the complete left part of your tree (the one before i is altered), will be written to array[0].
I'd suggest to share the array index among the function instances on the call stack. This can be achieved by passing a pointer to some i rather than passing i-s value around. And I'd introduce an internal version that does the work, because the user of the function needs not to be aware of the helper variable i:
void writeToArray_internal(struct node *root, int *array, int *i){
if(root != NULL){
writeToArray_internal(root->left, array, i);
array[*i] = root->key;
(*i)++;
writeToArray_internal(root->right, array, i);
}
}
void writeToArray(struct node *root, int *array) {
int i=0;
writeToArray_internal(root, array, &i);
}
This line here
int array_length = sizeof(array)/sizeof(array[0]);
is wrong. This only works with pure arrays, because sizeof returns the amount
of bytes of the expression/variable. Your variable array is a pointer, so
sizeof array returns you the size of a pointer and it doesn't matter where the
pointer is pointer, you always will get the same size.
Besides trying to get the number of elements of the "array" before knowing how
many nodes you have, makes no sense, because the number of elements that you need in array depend on the number of nodes, so
you've got write a function that returns you the number of nodes and then
you can allocate space for array.
Also note that your check function is not correct either. The variable i is
local to every call of check so you are going to overwrite values of the
array, because the i++ of the n-th iteration only affects the i of the
n-the iteration, the n-1-th iteration does not see that change and thus
overwrites the value of the n-th iteration.
You'll need to pass i as a pointer as well:
void check(struct node *root, int *array, size_t *i, size_t maxlen) {
if(root != NULL){
check(root->left, array, i, maxlen);
if(*i < maxlen) // checking that you don't step out of bounds
array[(*i)++] = root->key;
check(root->right, array, i, maxlen);
}
}
and the you call it like this:
size_t i = 0;
size_t nodes_number = get_number_of_nodes(root); // you have to write this function
int *array = malloc(nodes_number * sizeof *array);
if(array == NULL)
{
// error handling
// do not continue
}
check(root, array, &i, nodes_number);
Related
Objective
I am attempting to implement a binary tree sort in C from the pseudocode located at the wiki page on Tree Sort(https://en.wikipedia.org/wiki/Tree_sort).
Problem/Observation
Symptom: Segfault upon entering the InOrder function.
Within the TreeSort function(responsible for passing all of the collection items to the Insert function), after all of the insertions, but before I call the InOrder function which is responsible for printing the sorted tree node keys, I am losing my access to my root pointer. Because the root address is initialized within the same function that InOrder is called(TreeSort), I don't think I'm losing it due to a scope issue.
What I have done to fix the problem
Working function by function and watching the parameters through GDB compiler's debugger, I was able to see that all of the values in my source array/collection were properly initialized and each child node pointer was being properly allocated as needed. I have attempted to include print statements in my debugging to observe the state of certain parameters but none of them are printing and the program is going to directly to a SEGFAULT after I input the array length.
Note: I am aware that an error of 'segmentation fault' means I attempted to access restricted memory. The address has been lost. As such, the address passed to InOrder is 0x0, according to the GDB debugger.
Where the problem is located(to the best of my knowledge)
I have traced the address issue specifically to the line after initialization of all tree nodes when I call InOrder. I have included the full code at the behest of someone looking to assist me. It is listed below.
Additional comments
I am aware that I will need to destroy/free each of the initialized child Nodes that I have created. Because I am working on a basic implementation, I will add an appropriate function to handle the disposal of those nodes in the time it takes to receive a response, or shortly thereafter.
# include <stdio.h>
# include <stdlib.h>
# include <time.h>
typedef struct binTree binTree;
struct binTree {
binTree* leftNode;
binTree* rightNode;
int key;
};
void Insert(binTree* Node, int item);
void InOrder(binTree* Node);
void TreeSort(int* numberArr, int length);
binTree* createNode();
int* fillArray(int length);
int main() {
int* numberArray;
int lengthArray;
printf("Length of array of items: ");
scanf("%d", &lengthArray);
numberArray = fillArray(lengthArray);
TreeSort(numberArray, lengthArray);
free(numberArray);
return 0;
}
int* fillArray(int length) {
time_t t;
int* array = malloc(length * sizeof(int));
srand((unsigned) time(&t));
for(int i = 0; i < length; ++i) {
*(array + i) = (rand() % 50) + 1; // random num 1-50
}
for(int i = 0; i < length; ++i) {
printf("%d ", *(array + i));
}
return array;
}
void TreeSort(int* array, int length) {
binTree* root = calloc(1, sizeof(binTree)); // root
for(int i = 0; i < length; ++i) {
Insert(root, *(array + i));
}
InOrder(root);
}
void Insert(binTree* Node, int item) {
if(Node->key == 0) {
Node->key = item;
}
else {
if(item < Node->key) {
Node->leftNode = createNode();
Insert(Node->leftNode, item);
}
else {
Node->rightNode = createNode();
Insert(Node->rightNode, item);
}
}
}
void InOrder(binTree* Node) {
if(Node->key == 0) {
printf("Leaf found!\n");
}
else {
InOrder(Node->leftNode);
printf("Node: %d", Node->key);
InOrder(Node->rightNode);
}
}
binTree* createNode() {
binTree* Node;
Node = calloc(1, sizeof(binTree));
return Node;
}
Thank you in advance for your insight and advice.
Your InOrder function assumes that leaf nodes can be identified by checking if the key is zero.
However, your Insert function doesn't ensure that. Consequently you end up dereferencing a NULL pointer.
As a simple example consider a case with just a single element with value 42. When you call Insert your tree will become:
root -> --------------------
| key = 42 |
| rightNode = NULL |
| leftNode = NULL |
--------------------
Then call InOrder with this tree. The first call will be fine but the second call (recursive call) will pass a NULL pointer and then you do:
if(Node->key == 0)
which will crash because Node is NULL.
Also notice that your Insert function is wrong. It keeps adding new nodes directly under the root. That's wrong. You need to "go down" in the tree until you have a node where rightNode or leftNode is NULL. Then you can create a new node.
In other words - only do stuff like Node->leftNode = createNode(); when Node->leftNode is NULL.
Im trying to create a recursive function that creates an array of post order integers from a given tree. This is the code:
//structure
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;
// preorder_recursive is same as postorder_recursive(), except
// array[i] comes before the recursive calls
int *postorder_recursive(node *root)
{
int *array = malloc(sizeof(node) * node_count(root)); // node_count(root) counts nodes in binary tree
int i = 0;
if (root == NULL)
return 0;
while (root != NULL)
{
postorder_recursive(root->left);
postorder_recursive(root->right);
array[i] = root->data;
i++;
}
return array;
}
// returns 1 if pre order = post order, returns 0 otherwise
int compare(node *a, node *b)
{
int i = 0;
int *preArray, *postArray;
if (node_count(a) != node_count(b))
return 0;
preArray = preorder_recursive(a);
postArray = postorder_recursive(b);
for (i = 0; i < node_count(a); i++)
{
if (preArray[i] != postArray[i])
return 0;
}
free(preArray);
free(postArray);
return 1;
}
I am not entirely sure if the error is in this function, but if it is, it's probably due to the while loop. Any help would be great.
Edit: Ive included a lot more code. The purpose of this is to compare an array of post order to an array of pre-order.
Your function postorder_recursive() is creating a new array every time it is called. Furthermore, while(root != NULL) will loop forever for non-empty trees, if it weren't for the fact that it writes past the end of array and cause a segmentation fault at some point.
The solution is to split the function into one that creates the array, and then another function that recursively fills in the array, like so:
static size_t postorder_recursive(const node *root, int *array, size_t index) {
if (root == NULL)
return index;
index = postorder_recursive(root->left, array, index);
index = postorder_recursive(root->right, array, index);
array[index++] = root->data;
return index;
}
int *postorder_to_array(const node *root)
{
int *array = malloc(sizeof(node) * node_count(root));
postorder_recursive(root, array, 0);
return array;
}
So I wanted to write a function in C which converts a generic array into a single linked list.
The code I wrote:
typedef struct Node {
struct Node* next;
void *value;
} Node;
void insert(Node** root, void* value) {
Node* new_node = (Node *) malloc(sizeof(Node));
Node* ptr;
new_node->value = value;
new_node->next = NULL;
if (*root == NULL)
*root = new_node;
else {
ptr = *root;
while (ptr->next != NULL)
ptr = ptr->next;
ptr->next = new_node;
}
}
Node* arr2list(void* array, size_t length) {
Node *root = NULL;
for(int i = 0; i < length; i++) {
insert(&root,&array[i]);
}
return root;
}
I wrote a small test for it:
int main() {
int arr[] = { 1, 2, 3, 4, 5 };
int n = sizeof(arr) / sizeof(arr[0]);
Node* root = arr2list(arr, n);
while (root != NULL)
{
printf("%d,",*(int*) root->value);
root = root->next;
}
return 0;
}
But I get garbage values: -13308,-2145276560,-2145276560,-2145276560,-2145276560,.
I can't seem to find the mistake that leads to those results.
What could be the issue?
Your program contains &array[i] where array has type void* at line 28.
This is not standard C. GCC accepts it and treats the pointer arithmetic as char* arithmetic (arguably a bad idea, in particular because it feeds the confusion in an example such as this one).
Since your function arr2list consumes the array through some misaligned pointers, the results are apparently arbitrary values (that contain some of the bytes of the first array element and some of the bytes of the second array element, for instance).
I would be happy to say that the function arr2list must simply take as argument the length of one element, but this small change alone is not going to be enough in itself to make things work. Your linked list type stores pointers as data, so the function will also need to allocate a block for each of the elements, and store a pointer to this element inside the Node.
If you are content with making the list point to the elements of the array, then forget the above paragraph, you almost have a working solution, just make arr2list take an extra argument size_t elt_size and use (char*)array + elt_size*i instead of &array[i].
Using the qsort on a tree made of structs, I am not getting a sorted array back.
I've tried manipulating the comparator function and qsort but not sure what the problem is.
typedef struct nodeBST { // struct
char *key;
int count;
struct nodeBST *left;
struct nodeBST *right;
} nodeBST;
qsort(*words, numTokensActual, sizeof(nodeBST), comparator); //qsort
for (i = 0; i < numTokensActual; i++) {
printf("sorted words[%d]:%s: %d \n", i,
((struct nodeBST *)words[i])->key,
((struct nodeBST *)words[i])->count); //traverse to print
}
struct nodeBST *words[4]; //creation of array and malloc for space
int z;
for (z = 0; z < 4; z++) {
words[z] = malloc(sizeof(nodeBST));
}
int comparator(const void *p, const void *q) { //compare function
struct nodeBST *a = (struct nodeBST **)p;
struct nodeBST *b = (struct nodeBST **)q;
return a->count - b->count;
}
printf("%d \n"((struct nodeBST*)words[i])->count); //print output
int numTokensActual = AddToArray(root, words, 0);
int AddToArray(nodeBST *node, nodeBST **arr, int i) {
if (node == NULL)
return i;
if (node->left != NULL)
i = AddToArray(node->left, arr, i);
//printf("Adding To Array[%d]: %s:%d\n",i, node->key, node->count);
//arr[i] = node;
arr[i] = newNodeBST2(node->key, node->count);
//printf("added array[%d]: %s\n", i, arr[i]->key);
i++;
if (node->right != NULL)
i = AddToArray(node->right, arr, i);
return i;
}
I expect the output to give me a sorted array but the output is:
0
0
49
6
You don't have an array, read the documentation:
The qsort() function sorts an array with nmemb elements of size size.
We can use qsort to get a sorted list of the items without changing your data structure if you build a temporary array with count and a pointer to the items like:
struct {
int count;
struct nodeBST *node;
} tempSortedNodes[numTokensActual];
Traverse your tree and populate the sorted array, then you can qsort it. Note the sorted version becomes invalid when the tree is updated.
Another approach would be to have another tree using count as the key instead. That secondary tree would also be invalidated whenever the original tree is updated. However, we could update both trees if you need to maintain a count-sorted version of the tree all the times.
A sort algorithm for a tree, as suggested in the comments, is not a good idea at all. That would be equivalent to create a new tree using count as key as I suggested.
I'm trying to write a little program that goes through a list of numbers in an array and just inserts them into a binary search tree. Here's what I have:
#include <stdio.h>
#include <stdlib.h>
typedef struct node_t node_t;
struct node_t {
int data;
node_t *left;
node_t *right;
};
int insert(node_t *node, int n);
int main(void) {
int array[8] = {5, 8, 3, 6, 9, 2, 4, 7};
int i;
node_t *root;
for (i = 0; i < 8; i++) {
insert(root, array[i]);
}
return 0;
}
int insert(node_t *node, int n) {
if (node == NULL) {
node = malloc(sizeof node);
node->data = n;
return 1;
}
if (n > node->data) {
insert(node->left, n);
} else if (n < node->data) {
insert(node->right, n);
} else {
return -1;
}
return 0; // Suppress 'control reaches end of non-void function'
}
when I compile with gcc I get a warning saying "'root' may be used uninitialized in this function". Running it causes on errors (on Windows at least), however, printing out root->data in main() yields a 0.
The idea I was trying to implement was the insert() function checking if the pointer to the input node was NULL so it could then malloc it. Also, due to how the recursion is handled, the number being inserted should be inserted at that node. If the node did NOT equal NULL, then I would recursively call insert() again on the side of the node where the number should be inserted.
I understand the reason why this doesn't work has something to do with the pointer root not being directed anywhere, nor root->left/root->right, however, I don't know what I can do to fix this. Any help would be appreciated, thank you!
There might be more problem with the code you posted but I listed a few problems below.
Since it is the node that you need to allocate memory for if it contains NULL, you need to change this:
if (node->data == NULL) {
To this:
if (node == NULL) {
Also, you need to initiate the root node, since it will just contain whatever happens to be on stack at that moment and it may or may not be NULL (e.i. the thing you want to compare with in insert function). So initiate it like so:
node_t *root = NULL;
Last thing is to change to malloc to calloc function (or do a memset to zero on the memory separately). Otherwise the variables node->left and node->right can contain non NULL values that could result in making use of uninitialized memory.
Your program does indeed pass an unintialized root variable to the insert() function. But even if initialize root you are still going to have problems
because in order to populate the tree, you need to pass pointer to pointer (as you want to be able modify the pointer root in main()). Similarly, you need modify the argument to
the recursive calls to insert() as well.
I notice you don't really use the return value of insert(). So, it can just be a void function. I added some in-code comments to explain some problems.
#include <stdio.h>
#include <stdlib.h>
typedef struct node_t node_t;
struct node_t {
int data;
node_t *left;
node_t *right;
};
void print(node_t *r) { /* In order tree traversal. Gives the sorted output. */
if (!r) return;
print(r->left);
printf("%d ", r->data);
print(r->right);
}
void insert(node_t **node, int n);
int main(void) {
int array[] = {5, 8, 3, 6, 9, 2, 4, 7}; /* Removed the size. It can be calculated using sizeof and helps when array size changes */
int i;
node_t *root = NULL;
/* Without hard-coding, array size can be calculated like this. */
for (i = 0; i < sizeof array/sizeof array[0]; i++) {
insert(&root, array[i]);
}
print(root);
return 0;
}
void insert(node_t **node, int n) {
if (*node == NULL) {
*node = malloc(sizeof *node);
if (*node == NULL) { /* Need to check the return value for failure. */
perror("malloc");
exit(1);
}
(*node)->left = (*node)->right = NULL;
(*node)->data = n;
return;
}
if (n < (*node)->data) /* Insert smaller elements on the left for it to be a binary tree - but not neccessary */
insert(&(*node)->left, n);
else /* Another else below this isn't needed. There can't be any error with the number 'n' itself */
insert(&(*node)->right, n);
}