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.
Related
So I need to do a depth first search traversal of a given graph, however if a node in the graph has multiple adjacent neighbours, I need to choose the node with the lowest value to go to. So I implemented the following recursive depth first search function:
void DFS(struct Graph *graph, int vertex) {
struct node *adjList = graph->adjLists[vertex];
struct node *temp = adjList;
graph->visited[vertex] = 1;
printf("Visited %d \n", vertex);
int neighbouring_nodes[graph->numVertices];
while (temp != NULL) {
int count = 0;
struct node *temp_cpy = temp;
while (temp_cpy != NULL) {
neighbouring_nodes[count] = temp_cpy->vertex;
count++;
temp_cpy = temp_cpy->next;
}
int smallest_node = neighbouring_nodes[0];
for (int i = 0; i < count; i++) {
if (neighbouring_nodes[i] < smallest_node) {
smallest_node = neighbouring_nodes[i];
}
}
if (graph->visited[smallest_node] == 0) {
DFS(graph, smallest_node);
} else if (graph->visited[smallest_node] == 1 && count == 1) {
//if the node is visited but is it the only neighbour
DFS(graph, smallest_node);
}
temp = temp->next;
}
}
But when I run my program, it results in an infinite loop. I think I know why I am getting an infinite loop, it might be because there is never a return condition, so the recursive function just keeps running?
Is this type of depth first search possible with a recursive function? If yes, where am I going wrong? If no, how would I do it iteratively?
Help would be much appreciated.
Below is my full program without the DFS function:
// DFS algorithm in C
#include <stdio.h>
#include <stdlib.h>
struct node {
int vertex;
struct node *next;
};
struct node *createNode(int v);
struct Graph {
int numVertices;
int *visited;
struct node **adjLists;
};
// Create a node
struct node *createNode(int v) {
struct node *newNode = malloc(sizeof(struct node));
newNode->vertex = v;
newNode->next = NULL;
return newNode;
}
// Create graph
struct Graph *createGraph(int vertices) {
struct Graph *graph = malloc(sizeof(struct Graph));
graph->numVertices = vertices;
graph->adjLists = malloc(vertices * sizeof(struct node*));
graph->visited = malloc(vertices * sizeof(int));
int i;
for (i = 0; i < vertices; i++) {
graph->adjLists[i] = NULL;
graph->visited[i] = 0;
}
return graph;
}
// Add edge
void addEdge(struct Graph *graph, int src, int dest) {
// Add edge from src to dest
struct node *newNode = createNode(dest);
newNode->next = graph->adjLists[src];
graph->adjLists[src] = newNode;
// Add edge from dest to src
newNode = createNode(src);
newNode->next = graph->adjLists[dest];
graph->adjLists[dest] = newNode;
}
// Print the graph
void printGraph(struct Graph *graph) {
int v;
for (v = 0; v < graph->numVertices; v++) {
struct node *temp = graph->adjLists[v];
printf("\n Adjacency list of vertex %d\n ", v);
while (temp) {
printf("%d -> ", temp->vertex);
temp = temp->next;
}
printf("\n");
}
}
int main() {
struct Graph *graph = createGraph(4);
addEdge(graph, 0, 1);
addEdge(graph, 0, 2);
addEdge(graph, 1, 2);
addEdge(graph, 2, 3);
printGraph(graph);
DFS(graph, 2);
return 0;
}
"if a node in the graph has multiple adjacent neighbours, I need to choose the node with the lowest value to go to."
I assume the 'value' of a node is an attribute of the node object?
Most implementations of DFS will first look at the node with the lowest index in the data structure containing the node objects. So, if you first sort the nodes in your data structure into ascending value order, then the DFS will do what you want without needing to change the DFS code.
Here is what I came up with:
void DFS(struct Graph* graph, int vertex) {
struct node* temp = graph->adjLists[vertex];
graph->visited[vertex] = 1;
printf("Visited %d \n", vertex);
int neighbouring_nodes[graph->numVertices];
int count = 0;
while(temp != NULL) {
neighbouring_nodes[count] = temp->vertex;
count++;
temp = temp->next;
}
int smallest_node = neighbouring_nodes[0];
// Need to search (at most) in every neighbouring node
for (int i = 0; i < count; i++) {
// Go through all nodes in neighbouring_nodes array in order
// to find the smallest unvisited one, if it exists
for (int j = 0; j < count; j++){
// if current smallest_node has already been visited and
// neighbouring_nodes[j] is unvisited, assign it to smallest_node
if (graph->visited[smallest_node] == 1 && graph->visited[neighbouring_nodes[j]] == 0){
smallest_node = neighbouring_nodes[j];
}
// if neighbouring_nodes[j] is smaller than smallest_node,
// assign it to smallest_node
if (graph->visited[neighbouring_nodes[j]] == 0 && neighbouring_nodes[j] < smallest_node){
smallest_node = neighbouring_nodes[j];
}
}
if (graph->visited[smallest_node] == 0){
// calls DFS on the smallest unvisited neighboring node, if it exists
DFS(graph, smallest_node);
}else{
// otherwise (all neighboring nodes already visited)
// return control to the caller function
return;
}
}
}
I'm not 100% sure I understood what you wanted to do with the while (temp != NULL) and while (temp_cpy != NULL) loops but couldn't really figure out a way to use this approach especially in your particular case in which you want to visit the neighboring nodes in ascending order.
Let's assume a simple graph like 6->0->1, calling DFS(g, 0) will get temp to point to 6->1->NULL (could be also 1->6->NULL, depending on how you construct the graph), then smallest_node will be 1 and therefore the node 1 will be visited and the temp = temp->next will "assign" 1->NULL to temp. Back to the beginning of the loop, now temp_cpy will "be equal" to temp, hence 1->NULL. The node 6 is not on the list anymore even if it was not visited, on the other hand the already visited node 1 is still there. Also count is now equal to 1 therefore the condition (graph->visited[smallest_node] == 1 && count == 1) is met and DFS(g, 1) is called, which should not since node 1 was already visited. The infinite loop arises from this, since the previous condition is always met when temp has one (already visited) element left ([some value]->NULL). Once you reach that point you always call DFS(g, [some value]) and this will never give back control, since before reaching the temp = temp->next statement (which should assign NULL to temp , hence ending the while loop), DFS(g, [some other value]) is again called, which at some point will again call DFS(g, [some value]), and so forth.
As mentioned, one problem your original code has is that you call the DFS function also for an already visited vertex, and this should never be the case. When you encounter an already visited neighboring vertex, you want either to check the next or, if there are no unvisited neighboring vertices left, to give back control to the caller function. Therefore the last if else statement should not be there. The second problem is that smallest_node is selected in the wrong way. This is because temp_cpy, as explained above, is not constructed in such a way that it necessarily contains all unvisited neighboring nodes and also because you're actually looking for the smallest element in this list, regardless if it has already been visited or not (again because of the assumption that temp_cpy contains only all unvisited nodes). In fact you should be looking for the "smallest unvisited node" rather than the "smallest node".
In my code I go through all neighboring nodes with two for loops, find the smallest unvisited one and call DFS(g, [smallest unvisited node]) and once there are no unvisited neighbors left, return control back to the caller function.
I Hope this is somewhat understandable and I also hope I'm not missing something about what you had in mind with your implementation, in which case I would be very much interested in some explanations!
Here is a simpler version of the DFS in which neighboring nodes are checked and eventually visited in the order they're presented in the adjList. In this case I think the while (temp != NULL)/temp = temp->next approach makes sense:
void DFS(struct Graph *graph, int vertex) {
struct node *temp = graph->adjLists[vertex];
graph->visited[vertex] = 1;
printf("Visited %d \n", vertex);
// for vertex search in every neighboring node
while (temp != NULL) {
// if neighboring vertex temp->vertex not visited, then search there
if (graph->visited[temp->vertex] == 0) {
DFS(graph, temp->vertex);
// if already visited, go to the next vertex on the neighbors list
}else{
temp = temp->next;
}
}
// when searched in all neighboring vertexes return control to caller
return;
}
struct Node {
char*label;
struct Node *children;
};
I am trying to traverse a tree and print the value/label of the nodes(as defined above) based on the current depth.
Output:
Output
My code:
void recurse_helper(struct Node **root, int level, int max_level){
if (level > max_level){
return;
}
struct Node* r = *root;
if(r->children == NULL){
}
else{
struct Node *current = r->children;
}
void traverse_and_print(struct Node* root, max_dep){
recurse_helper(&root, 0,max_dep);
}
My code doesn't seem to work properly. Does anyone have a better recursive solution or could someone please recommend how to change my current implementation?
This seemed to do the trick.
void printTree(Node *root, int level) {
if (root == NULL)
return;
for (int i = 0; i < level; i++) {
printf(" ");
}
printf("%s\n", root->data);
for (Node *child = root->children; child != NULL; child = child->next_sib) {
printTree(child, level + 1);
}
}
It doesn't implement max_level, I'll leave that to you to ad.
One obvious problem seems to be....you are calling recurse_helper() with max_level = 0 :
recurse_helper(&root, 0,0);
which you stated meant print out the entire tree, however this line in recurse_helper():
if (level > max_level){
return;
}
will cause the recursion to stop after the first iteration. The second call to recurse_helper() will pass in 1 for level and 0 for max_level:
recurse_helper(&((r->children)->children), level+1, max_level);
So you definitely need to specifically account for max_level = 0.
You didn't describe the erroneous behavior you were seeing, but this certainly seems like an issue.
For a binary search tree structure in C that cannot be changed:
struct bstnode {
int item;
struct bstnode* left;
struct bstnode* right;
};
struct bst {
struct bstnode* root;
};
How can we find the sum of values that are greater than a number(num)?
(we cannot travel the whole tree or convert this bst to an array).
the function declaration is:
int sum_greater(struct bst * t, int num)
Basically, my method is to use recursion:
when num equals item in the current node, we sum the right part of this tree.
when num greater than item in the current node and node->right is greater than num, we sum the right part of this tree.
But I dont know how to deal with the situation when current node is less than num.
You're making this a bit too complicated. Your base case is hitting a leaf node (which you already know how to handle). You have three recursion cases:
current > num
result = current +
recur on right child +
recur on left child
current = num
result = current +
recur on right child
current < num
result = recur on right child
return result
All you can do is to prune off the left subtrees that are too small as you find them. don't waste effort looking ahead: the recursion will handle that just fine.
Note that you cannot stop early dependent on the right child's value: that child may well have right-descendants with arbitrarily large values.
So the user #Prune has already pointed out the idea which consists of getting ride of sub trees that are less than the desired value.
int sum_greater(struct bst * t, int num){
struct bstnode *ptr = t->root;
if(!ptr)
return 0;
struct bst right_tree = { t->root->right };
struct bst left_tree = { t->root->left };
if(ptr->item > num)
return ptr->item + \
sum_greater(&left_tree, num) + \
sum_greater(&right_tree, num);
else // ptr->item =< num
return sum_greater(&right_tree, num);
}
For a complete example, run the code from : Full sum_greater code
how to deal with the situation when current node is less than num.
Only add the right BST in that case, when current node is less than or equal to num. Else add both left, right and the ->item.
int BST_sum_gt(const struct bstnode* node, int num) {
if (node == NULL) {
return 0;
}
if (node->item > num) {
return BST_sum_gt(node->left) + node->item + BST_sum_gt(node->left);
}
return BST_sum_gt(node->left);
}
int sum_greater(const struct bst * t, int num) {
return BST_sum_gt(t->root);
}
Or a less recursive approach
int BST_sum_gt(const struct bstnode* node, int num) {
int sum = 0;
while (node) {
if (node->item > num) {
sum += BST_sum_gt(node->left) + node->item;
}
node = node->right;
}
return sum;
}
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);
}
I am not too good at making trees and I totally screw up recursion. However, I attempted to make a program to insert and display data into the tree.
The problem is that it crashes after inserting into the root node and I do not know why. The tree is not too big. Just 10 int.
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
struct node{
int data;
struct node * left;
struct node * right;
};
void insert(struct node * root,int num){
printf("Insert called for num:%d\n",num);
if(root == NULL){
root = (struct node *)malloc(sizeof(struct node));
root->data = num;
}else if(num > root->data){ // Number greater than root ?
insert(root->right,num); // Let the right sub-tree deal with it
}else if(num < root->data){// Number less than root ?
insert(root->left,num);// Let the left sub-tree deal with it.
}else{
// nothing, just return.
}
}
void display(struct node * root){ // Inorder traversal
if(root->left!=NULL){ // We still have children in left sub-tree ?
display(root->left); // Display them.
}
printf("%d",root->data); // Display the root data
if(root->right!=NULL){ // We still have children in right sub-tree ?
display(root->right); // Display them.
}
}
int main(int argc, char *argv[]) {
int a[10] = {2,1,3,5,4,6,7,9,8,10};
int i;
struct node * tree;
for(i = 0; i < 10;i++){
insert(tree,a[i]);
}
printf("Insert done");
return 0;
}
Can someone please tell me where I went wrong ?
I know it is frowned upon to ask people to review your code on Stack but sometimes pair programming works :p
Update:
After setting struct node * tree = NULL;, the insert() method works well. The display() causes program to crash.
in your
int main(int argc, char *argv[]) {
// ...
struct node * tree;
// what is the value of tree at this line?
for(i = 0; i < 10;i++){
insert(tree,a[i]);
}
// ...
}
what does "tree" point to at the line marked?