i am having a normal binary tree that i am trying to apply iterative deepening depth first search on using c :
struct node {
int data;
struct node * right;
struct node * left;
};
typedef struct node node;
and i am using a function to insert nodes into tree, now i need to implement the search function to be something like this:
function search(root,goal,maxLevel)
so it search using depth first search but to a specific max level then stop
that was my first try,it doesn't work :
currentLevel = 0;
void search(node ** tree, int val, int depth)
{
if(currentLevel <= depth) {
currentLevel++;
if((*tree)->data == val)
{
printf("found , current level = %i , depth = %i", currentLevel,depth);
} else if((*tree)->left!= NULL && (*tree)->right!= NULL)
{
search(&(*tree)->left, val, depth);
search(&(*tree)->right, val, depth);
}
}
}
please help, thanks ...
You never stop...
node *search(node ** tree, int val, int depth)
{
if (depth <= 0)
{
return NULL; // not found
}
if((*tree)->data == val)
{
return *tree;
}
if((*tree)->left)
{
node * left = search(&(*tree)->left, val, depth - 1);
if (left) return left; // found
}
if((*tree)->right)
{
node * right = search(&(*tree)->left, val, depth - 1);
return right; // whatever is result of right
}
return NULL; // not found
}
The global variable won't work for this. You want to have something like
void search(node ** tree, int val, int remainingDepth) {
if (remainingDepth == 0) return;
then
search(&(*tree)->left, val, remainingDepth - 1);
search(&(*tree)->right, val, remainingDepth - 1);
You probably also want to check left & right for null separately, as each could be independently null.
Related
I am writing a function to check whether a tree is a perfect binary tree and here is my code:
#include "binary_trees.h"
/**
* binary_tree_is_perfect - checks if a binary tree is perfect
* #tree: is a pointer to the root node of the tree to check
*
* Return: If the tree is perfect, it returns 1. Otherwise, it
* returns 0.
*/
int binary_tree_is_perfect(const binary_tree_t *tree)
{
int check, depth, level;
if (tree == NULL)
return (0);
level = 0;
depth = find_depth_left(tree);
check = isPerfect(tree, depth, level);
return (check);
}
/**
* find_depth_left - finds the depth of the left most leaf
* in a binary tree
* #tree: is a pointer to the tree to measure the left most
* depth
*
* Return: The depth of the left most node
*/
int find_depth_left(const binary_tree_t *tree)
{
if (!tree->left)
return (0);
return (1 + find_depth_left(tree->left));
}
/**
* isPerfect - helper function to find if a binary tree is perfect
* #depth: this is the left most depth of the tree
* #level: this is the level where to the check is happening
*
* Return: If the tree is perfect, it returns 1. Otherwise, it
* returns 0.
*/
int isPerfect(const binary_tree_t *tree, int depth, int level)
{
if (!tree->left && !tree->right)
return (depth == (level + 1));
if (!tree->left || !tree->right)
return (0);
return (isPerfect(tree->left, depth, level + 1) &&
isPerfect(tree->right, depth, level + 1));
}
My logic: I will find the left most leaf node of the tree (this is just my choice), then I will check whether the nodes will have two children or none with isPerfect function.
But for every tree I input, I get 0 (meaning the tree is not perfect). This happens even if the tree is a perfect binary tree. Where did my logic go wrong?
First the code was well thought out.
The internal (recursive) functions work on a non-null node.
That would be fine for a OOP, object oriented programming, language, as then
the function could be a member function on the node class binary_tree_t.
However here it led to difficulty: find_depth on a single node tree would logically be 1, not 0.
You could write it with accepting tree parameters as null.
Then level and depth coincide.
bool binary_tree_is_perfect(const binary_tree_t *tree)
{
int depth = find_depth_left(tree);
int level = 0;
bool check = isPerfect(tree, depth, level);
return check;
}
int find_depth_left(const binary_tree_t *tree)
{
if (!tree)
return 0;
return 1 + find_depth_left(tree->left);
}
bool isPerfect(const binary_tree_t *tree, int depth, int level)
{
if (!tree)
return level == depth;
if (!tree->left != !tree->right)
return false;
return isPerfect(tree->left, depth, level) &&
isPerfect(tree->right, depth, level);
}
So it was a semantic (=in meanding) difference between level and depth.
For the logic it would have been better to use one variable: expectedDepth.
bool binary_tree_is_perfect(const binary_tree_t *tree)
{
int expectedDepth = find_depth_left(tree);
bool check = isPerfect(tree, expectedDepth);
return check;
}
int find_depth_left(const binary_tree_t *tree)
{
return !tree ? 0 : 1 + find_depth_left(tree->left);
}
bool isPerfect(const binary_tree_t *tree, int expectedDepth)
{
if (!tree)
return 0 == expectedDepth;
if (!tree->left != !tree->right)
return false;
return expectedDepth >= 0 &&
isPerfect(tree->left, exoectedDepth - 1l) &&
isPerfect(tree->right, expectedDepth - 1);
}
expectedDepth >= 0 && is probably not needed as you took the expected depth from the left most leaf, as then the left subtree's isPerfect will return false. Interesting is it not?
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 am doing a C BST library and im trying to do a function that will save the binary search tree into a text file.I am quite confuse on how to do it.Heres my tree structure:
struct Node {
int value;
struct Node *left;
struct Node *right;
};
typedef struct Node TNode;
typedef struct Node *binary_tree;
Creation of the tree:
binary_tree NewBinaryTree(int value_root) {
binary_tree newRoot = malloc(sizeof(TNode));
if (newRoot) {
newRoot->value = value_root;
newRoot->left = NULL;
newRoot->right = NULL;
}
return newRoot;
}
Adding elements to it:
void Insert(binary_tree *tree, int val) {
if (*tree == NULL) {
*tree = (binary_tree)malloc(sizeof(TNode));
(*tree)->value = val;
(*tree)->left = NULL;
(*tree)->right = NULL;
} else {
if (val < (*tree)->value) {
Insert(&(*tree)->left, val);
} else {
Insert(&(*tree)->right, val);
}
}
}
I did a start of the function but I dont know how to do this:
void savetree(binary_tree *tree, char * filename)
{
FILE *afile;
int remainn, counter, readsize, i;
int *bb;
afile = fopen(filename, "wb");
if (afile) {
bb = calloc(sizeof(int), BBSIZE); //BBSIZE =4096
remainn = treesize(tree);
counter = 0;
while (remainn > 0) {
if (remainn > BBSIZE) {
readsize = BBSIZE;
} else {
readsize = remainn;
}
Heres the treesize function:
int treesize( binary_tree tree )
{
if( tree == NULL )
{
return (0) ;
}
else
{
return( 1 + treesize( tree->left ) + treesize( tree->right ) ) ;
}
}
This savetree function is not completed but im not sure on how to complete it/if what I did is correct.
thank you
Nested parentheses and trees are alternative representations for the same thing.
So writing a tree is easy
void writenode(Node *node)
{
printf("{");
printf("%d ", node-.value);
if(node->left)
writenode(node->left);
if(node->right)
writenode(node->right);
printf("}");
}
Reading is quite a bit harder. You have to detect malformed input, and construct the children recursively.
The easiest way to save binary tree to a txt file is saving them as an array. Only downside is you will waste space because it will save the binary tree as complete binary tree.
It is easy to write and even to read. Because left, right child and parent of node at ith index can be found as:
int left(int i) {
return 2*i + 1;
}
int right(int i) {
return 2*i + 2;
}
int parent(int i) {
return (i-1)/2;
}
For a sparse binary tree(Binary tree which has rare nodes but height is very), One method is save its preorder and postorder traversals and then rebuild this binary tree from these two traversals to avoid saving many NULL bytes as suggested by Dulguun.
Some examples: Construct Full Binary Tree from given preorder and postorder traversals
In one of the C exercises I had to create a function for binary tree traversal with a given depth.
My first thought was to use a for loop (traverse_preorder_bad). Finally, I could complete the task with a variable initialization + if (traverse_preorder_working), but I am still struggling to understand why the for solution didn't work.
Could someone explain me the difference? Is there an elegant solution?
Code on Ideone
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
const int RANGE = 1000;
typedef struct node_t
{
int data;
struct node_t *left;
struct node_t *right;
} node_t;
node_t *node_new(int data);
node_t *node_insert(node_t *tree, int data);
void traverse_preorder_working(node_t *tree, int depth);
void traverse_preorder_bad(node_t *tree, int depth);
int main(int argc, char *argv[])
{
node_t *tree = NULL;
// Random seed
srand((unsigned) time(NULL));
// Create the root node
tree = node_new(rand() % RANGE);
node_insert(tree, 5);
node_insert(tree, 1);
printf("Expected output:\n");
traverse_preorder_working(tree, 10);
printf("Bad output:\n");
traverse_preorder_bad(tree, 10);
return 0;
}
node_t *node_new(int data)
{
node_t *tree;
tree = malloc(sizeof(*tree));
tree->left = NULL;
tree->right = NULL;
tree->data = data;
return tree;
}
node_t *node_insert(node_t *tree, int data)
{
if (!tree)
return node_new(data);
if (data == tree->data)
return tree;
if (data < tree->data)
tree->left = node_insert(tree->left, data);
else
tree->right = node_insert(tree->right, data);
return tree;
}
void traverse_preorder_working(node_t *tree, int depth)
{
int i;
if (!tree)
return;
printf("%d\n", tree->data);
i = 1;
if (tree->left && i <= depth)
{
traverse_preorder_working(tree->left, depth - i);
i++;
}
i = 1;
if (tree->right && i <= depth)
{
traverse_preorder_working(tree->right, depth - i);
i++;
}
}
void traverse_preorder_bad(node_t *tree, int depth)
{
if (!tree)
return;
printf("%d\n", tree->data);
for (int i = 1; tree->left && i <= depth; i++)
traverse_preorder_bad(tree->left, depth - i);
for (int i = 1; tree->right && i <= depth; i++)
traverse_preorder_bad(tree->right, depth - i);
}
The problem is that traverse_preorder_working is correctly recursive, when visiting a node you call traverse_preorder_working recursively on the left subtree (and then right)
Instead traverse_preorder_bad is still recursive but it makes no sense, when you visit a node you then call traverse_preorder_bad n-times on the same subtree with a different depth.
If you check invocation tree for something like:
a
/ \
b c
/ \ / \
d e f g
You can see that traverse_preorder_working(a,5) goes traverse_preorder_working(b,4), traverse_preorder_working(d,3) .. while other function goes
traverse_preorder_bad(a,5),
traverse_preorder_bad(b,4), visit subtree
traverse_preorder_bad(b,3), visit subtree
traverse_preorder_bad(b,2), visit subtree
traverse_preorder_bad(b,1), visit subtree ...
from the same level of recursion, which means that each node will be visited multiple times with different depth limits; this doesn't happen in the first correct version.
If each invocation of traverse_preorder_bad should visit a node and start visiting both subtrees but inside the code you call visit recursively more than twice (which is the case, since you have a loop) then something is wrong.
The "for" version make no sense. You only want to print the tree for a given node once, so you should only call traverse on each node once.
Additionally, based on one of your comments in your post, I think you have some misunderstandings about your working function.
You have multiple checks for whether the tree is null (both as the current tree or as its children)
i ever only has a value of one while it is being used. You could simplify to
void traverse_preorder_working(node_t *tree, int depth){
if(!tree || depth <= 0){
return;
}
printf("%d\n", tree->data);
traverse_preorder_working(tree->left, depth - 1);
traverse_preorder_working(tree->right, depth - 1);
}
All of the checks to see if we not should explore a node - either because it doesn't exist or it is too deep - are done only once (at the start of the function), and not repeated twice for each child. No i variable that does nothing.
The elegant solution here (without recursion) is Morris Traversal. The idea is to add indirection edge from the left subtree's rightmost node to the current node.
The full explanation of the algorithm is here: http://www.geeksforgeeks.org/inorder-tree-traversal-without-recursion-and-without-stack/
Of course you can modify this algorithm not to go deeper then you current depth.
I was working on the exercises here :
"http://cslibrary.stanford.edu/110/BinaryTrees.html#s2"
I wrote a function that decides if a Tree is a BST(return 1) or not(return 0) but I'm not sure if my code is totally good, I tested it for a BST and a non-BST Tree and it seems to work correctly. I want to know the opinion of the community :
Updated Code :
consider the Tree ( not a BST ) :
5
/ \
2 7
/ \
1 6
my Idea is to compare 2 with 5 if it's good, then 1 with 5, and if it's good then 6 with 5 if it's good then 1 with 2 if it's good then 6 with 2 if it's good then 5 with 7 ; if it's good isBST() returns 1. this code is supposed to do it recursively.
the node structure :
struct node {
int data;
struct node* left;
struct node* right;
};
the code :
int lisgood(struct node* n1,struct node* n2)
{
if(n2 == NULL)
return 1;
else{
int r = lisgood(n1,n2->left)*lisgood(n1,n2->right);
if(r){
if(n1->data >= n2->data)
{
return r;
}
else return 0;
}
else return r;
}
}
int risgood(struct node* n1,struct node* n2)
{
if(n2 == NULL)
return 1;
else{
int r = risgood(n1,n2->right)*risgood(n1,n2->left);
if(r){
if(n1->data < n2->data)
{
return r;
}
else return 0;
}
else return r;
}
}
int isBST(struct node* node)
{
if(node == NULL)
return 1;
else{
if(lisgood(node,node->left)&&risgood(node,node->right)){
return (isBST(node->left)&&isBST(node->right));
}
else return 0;
}
}
Your code doesn't really work - not even for the example you showed. You never compare 5 to 6. Basically you are comparing the root of a sub-tree with root->left, root->left->left, root->left->left->left, etc. Then you are comparing root with root->right, root->right->right, etc., but you never compare root with the other nodes in the subtree. The problem is that you don't compare a tree's root with every element on its right and left subtrees, and you should.
This is a known interview question. The simpler way to solve it is to pass in the minimum and maximum values allowed for a sub-tree as parameters.
Here's how it works with the example tree you showed: you see 5, thus, the maximum value for any node on 5's left subtree is 5. Similarly, the minimum value for any node on 5's right subtree is 5. This property is applied recursively to check that every node's value is consistent with the requirements. Here's a working implementation (assumes a tree with no duplicates):
#include <stdio.h>
#include <limits.h>
struct tree_node {
int key;
struct tree_node *left;
struct tree_node *right;
};
static int is_bst_aux(struct tree_node *root, int min, int max) {
if (root == NULL) {
return 1;
}
if (!(min < root->key && root->key < max)) {
return 0;
}
if (!is_bst_aux(root->left, min, root->key)) {
return 0;
}
return is_bst_aux(root->right, root->key, max);
}
int is_bst(struct tree_node *root) {
return is_bst_aux(root, INT_MIN, INT_MAX);
}