Binary search tree traversal in C - c

I have this function that traverses a binary search tree and appends nodes to a list if they are between a given lower and upper bound.
// n - the current node
// l - a list to accumulate results
static void doTreeSearchBetween(Tree t, Node n, Record lower,
Record upper, List l) {
// empty tree
if (n == NULL) {
return;
}
int cmpUpper = t->compare(n->rec, upper);
int cmpLower = t->compare(n->rec, lower);
// search left subtree
doTreeSearchBetween(t, n->left, lower, upper, l);
// if node if between lower and upper records append to list
if (cmpLower >= 0 && cmpUpper <= 0) {
ListAppend(l, n->rec);
}
// search right subtree
doTreeSearchBetween(t, n->right, lower, upper, l);
}
I realised the issue with this code is that it traverses the entirety of the list in-order, making it very inefficient and I'm looking for a way that would allow me to visit as few nodes as possible. The logic isn't working out for me, I was wondering if anyone had any ideas? I tried adding a couple if statements for whenever the current node is less than the lower and greater than the upper bound, that didn't work out for me.
An example of the output:
Inserting: 11 13 17 19 23 29 31 37 41 43
Searching between 10 and 20
Search returned: 11 13 17 19
Type defs:
typedef struct node *Node;
struct node {
Record rec;
Node left;
Node right;
};
struct tree {
Node root;
int (*compare)(Record, Record);
};
struct list {
Record *items;
int numItems;
int maxItems;
};
struct record {
char familyName[MAX_FAMILY_NAME_LENGTH + 1];
char givenName[MAX_GIVEN_NAME_LENGTH + 1];
};

You should rely on the comparisons to determine whether to recurse on the left and/or right branches:
if the tree node is below the lower bound, its left subtree can be pruned.
if the tree node is above the upper bound, its right subtree can be pruned.
Assuming it is empty at the root node, the list will be sorted by construction.
// n - the current node
// l - a list to accumulate results
static void doTreeSearchBetween(Tree t, Node n, Record lower,
Record upper, List l) {
// empty tree
if (n == NULL) {
return;
}
int cmpUpper = t->compare(n->rec, upper);
int cmpLower = t->compare(n->rec, lower);
if (cmpLower >= 0) {
// search left subtree
doTreeSearchBetween(t, n->left, lower, upper, l);
// if node if between lower and upper records append to list
if (cmpUpper <= 0) {
ListAppend(l, n->rec);
}
}
if (cmpUpper <= 0) {
// search right subtree
doTreeSearchBetween(t, n->right, lower, upper, l);
}
}

Related

How would you get a list of height unbalanced leaf nodes in a binary search tree?

To know whether a tree is height balanced or not we simply compare the height of left and right sub trees.
However, how do I create a program that will tell me how many nodes are unbalanced and print out those nodes?
As with all things trees: use recursion.
int num_unbalanced(node* root, int* height_out, int should_print) {
if (!root) { *height_out = 0; return 0; }
int left_height, right_height;
int left_unbalanced = num_unbalanced(root->left, &left_height, should_print);
int right_unbalanced = num_unbalanced(root->right, &right_height, should_print);
int this_unbalanced = abs(left_height - right_height) > 1;
*height_out = 1 + max(left_height, right_height);
if (should_print && this_unbalanced) print_node(root);
return left_unbalanced + right_unbalanced + this_unbalanced;
}

Print the count of even values at odd levels from a Binary Search Tree

I have a binary search tree and I need to print the total count of even values that are at odd levels.
I have an algorithm to do the traversal in order, but I don't know how to make it count the level of the tree to know if a given even value is at an odd level.
Inorder algorithm
void printInOrder(Node *root)
{
if (root != NULL)
{
printInOrder(root->left);
printf("%d ", root->key);
printInOrder(root->right);
}
(the level count starts at zero where the root is)
Example 1:
BST
number of even keys that are at odd levels: 2
Example 2:
BST 2
number of even keys that are at odd levels: 6
I'm really lost, any help is welcome.
To print the total count of even values that are at odd levels, you need to keep a global variable, that will store the count of even nodes.
You need to traverse the tree inOrder wise, and only traverse over the given level for odd nodes.
I am attaching the code snippet below. Print the variable c to get the required result.
int c=0; // Maintain a global variable to keep count
int printLevelOrder()
{
int h = height(root);
for(int i=1;i<=h;i++) // i=1 -> level 0
{
if( (i-1)%2 != 0) // level start from 0 and height from 1. traverse only for odd levels
{
evenNode(root, i);
}
}
}
// fn to calculate the height of BST
int height(Node root)
{
if(root == null)
return 1;
else
{
int lheight = height(root.left);
int rheight = height(root.right);
if(lheight > rheight)
return lheight;
else
return rheight;
}
}
// traversing at a given level
void evenNode(Node root, int level)
{
if(root == null)
return ;
if(level ==1)
{
if(root.data %2 == 0) // check if bode is even then increase counter.
c++;
}
else if(level > 1)
{
evenNode(root.left , level -1);
evenNode(root.right, level - 1);
}
}
You could do something like this :
void printInOrder(Node *root, int level)
{
if (root != NULL)
{
if (level & 1) {
// Do something at odd level only
}
printInOrder(root->left, level+1);
printInOrder(root->right, level+1);
}
}

Adjacency List in C for undirected (unweighted) graph

Here is my code:
#define V 5
typedef struct edge* link;
//structure for reprenting edges
typedef struct edge{
int dst; //number of destination node
//int weight; //for weigthed graphs
link next; //link to next edge
} edge_t;
link new_edge(int dst, link next) {
link edge = (link) malloc(sizeof(edge_t));
edge->dst = dst;
edge->next = next;
return edge;
}
int main() {
link edge;
link adj[V];
//the array contains V pointers to lists of edges
//each list for each node of my graph
int i;
int j;
//all lists are empty at beginning
for (i = 0; i < V; i ++) {
adj[i] = NULL;
}
printf("input the edges:\n");
while (scanf("%d %d", &i, &j) == 2) {
adj[i] = new_edge(j, adj[i]);
//in the list for node i
//put the edge to node j
adj[j] = new_edge(i, adj[j]); //if it is undirect
//in the list for node j
//put the edge to node i
}
printf("adjacency list is: \n");
//cycle over the nodes
for (i=0; i<V; i++) {
if (adj[i] == NULL) {
printf("%d is null list\n", i);
}
//print all the edges for that node
for (edge = adj[i]; edge != NULL; edge = edge -> next) {
printf("edge %d -> %d\n", i, edge->dst);
}
}
}
INPUT:
0 1
0 2
1 3
stop
OUTPUT:
adjacency list is:
edge 0 -> 2
edge 0 -> 1
edge 1 -> 3
edge 1 -> 0
edge 2 -> 0
edge 3 -> 1
4 is null list
This image shows how my new_edge function works, blue area(in pic) is changing so I can traverse through the list, so my question is why blue area is equal to NULL?, cause it is pointing to last item in the list, I thought it won't be NULL(P.S I verified it is null when I traversed through the list in order to print it).
The elements of adj are pointers to nodes, not nodes.
On the other hand, what next in the nodes point at are nodes, not pointers to nodes.
Therefore, next will not point at the elements of adj.
This is how your code actually work:
As you see, the pointers are not looping back and your blue area (elements of adj that have nodes added) is not equal to NULL.

Building a binary tree given the postorder and inorder traversals

Following this link, I modified the code to build a binary tree given the postorder and inorder traversals. But the output seems to generate some junk values. I couldn't understand where I have gone wrong. A preorder traversal has root at the beginning and a postorder traversal has root at the end. Using that logic, I modified the code. As follows:
struct tree* buildTree2(char in[], char post[], int inStrt, int inEnd)
{
static int postIndex = sizeof(post)/sizeof(post[0]) - 1; //postorder index
if(inStrt > inEnd)
return NULL;
struct tree* tNode = newNode(post[postIndex--]);
if(inStrt == inEnd)
return tNode;
else
{
int inIndex = search(in, inStrt, inEnd, tNode->data);
tNode->left = buildTree(in, post, inStrt, inIndex-1);
tNode->right = buildTree(in, post, inIndex+1, inEnd);
return tNode;
}
}
Output:
The inorder traversal of the build tree (using preorder traversal) is : D B E A F C
The inorder traversal of the build tree (using postorder traversal) is : D B I R O 7 = R N T V _ G D X t u o . a / .
Modified code:
struct tree* buildTree2(char in[], char post[], int inStrt, int inEnd, int postIndex)
{
//printf("\n %d ",postIndex);
if(inStrt > inEnd) //termination condition for buildTree(in, post, inIndex+1, inEnd)
return NULL;
struct tree* tNode = newNode(post[postIndex--]);
//check if node has children
if(inStrt == inEnd)
return tNode;
else
{
//get the index of the postorder variable in the inorder traversal
int inIndex = search(in, inStrt, inEnd, tNode->data);
//Recursively build the tree
tNode->left = buildTree2(in, post, inStrt, inIndex-1, postIndex);
//The inIndex value points to the tNode. So less than that is left sub tree and more than that is the right sub tree
tNode->right = buildTree2(in, post, inIndex+1, inEnd, postIndex);
return tNode;
}
}
Output:
The inorder traversal of the build tree (using preorder traversal) is : D B E A F C
The inorder traversal of the build tree (using postorder traversal) is : E B E
node<int> * consTree(int * post, int * in, int postS, int postE, int inS, int inE){
if(postS > postE)
return NULL;
int rootdata = post[postE];
int indexI = -1;
for(int i = inS; i <= inE; i++){
if(rootdata == in[i]){
indexI = i;
break;
}
}
int lpostS = postS;
int linS = inS;
int linE = indexI - 1;
int lpostE = postS + indexI - inS - 1;
int rpostS = postS + indexI - inS;
int rpostE = postE - 1;
int rinS = indexI + 1;
int rinE = inE;
node<int> * root = new node<int>(rootdata);
root -> left = consTree(post,in,lpostS,lpostE,linS,linE);
root -> right = consTree(post,in,rpostS,rpostE,rinS,rinE);
return root;
}
Basically you need to think , when the right order both traversal are passed in the recursive call the array passed remain same just the indexes are changed..in that case let say i have pass in right order traversal (arr,6,9) so the changes should be made between that indexes only.. not from the 0(starting index of array)

Measuring time in C

I'm writing a lab assignment for programming classes. I need to do it in C :). The task I choose looks as follows: I created three kinds of data types in C: linked list, binary tree and avl tree. All the data handle 5,000,000 elements. I need to measure how long it takes to find and not find element in certain step. I have fixed values for positive and negative findings.
Here is some of my code that contains function for creating array of 5,000,000 numbers and two function for binary tree adding and finding node. I hope that the code is quite clear.
#include <stdio.h>
#include <stdlib.h>
#define SIZE 5000000
typedef struct Node {
int data;
struct Node *left, *right;
} Node;
void evenArrayGen(int num, int even_nums[]);
void shuffle(int numbers[]);
void addNode(Node **root, int value);
Node* findNode(Node *root, int value);
/** Recursively adds given value to the tree
*
* #param root
* #param value
*
*/
void addNode(Node **root, int value) {
Node *temp;
///check statement to avoid infinite loop in adding
if(*root == NULL) {
temp = (Node*)malloc(sizeof(Node));
temp->data = value;
temp->left = temp->right = NULL;
*root = temp;
return;
}
///recursively check where to add node
///if smaller than the root add to the left
///if bigger than the root add to the right
else {
temp = *root;
if(value < temp->data) {
addNode(&(temp->left), value);
} else {
addNode(&(temp->right), value);
}
return;
}
}
/** Recursively searches for Node with given value
*
* #param root
* #param value
* #return Node or NULL (if Node was not found)
*
*/
Node* findNode(Node *root, int value) {
Node *temp;
///check statement to avoid infinite loop in searching
///if it reachese that point given value is not in the tree
if(root == NULL) {
// printf("Given value is not in the tree\n");
return NULL;
}
temp = root;
if(temp->data == value) {
// printf("Searched value is: %i\n", temp->data);
return temp;
} else if(value < temp->data) {
findNode(temp->left, value);
} else {
findNode(temp->right, value);
}
}
/** Generates array of ordered even numbers from 2
*
* #param num number of uniqe even digits
* #param array of size equal to the number
*
*/
void evenArrayGen(int num, int even_nums[]) {
int i, current;
i = current = 0;
for(; i<num; i++) {
even_nums[i] = current += 2;
}
return;
}
/** Shuffle the array in random order. Radomly gets the index between 0 and
* current last index. Swaps number at random index with last one and
* decreses the current_last index by 1.
*
* #param array of numbers to be shuffled
*
*/
void shuffle(int nums[]) {
int i, len, current_last, index, temp;
///set the current_last to length of the array to track index for
///swaping nums
current_last = len = SIZE;
for (i=0; i<len; i++) {
srand(time(NULL));
index = rand()%(current_last);
temp = nums[index];
nums[index] = nums[current_last];
nums[current_last] = temp;
current_last--;
}
return;
}
int main() {
//initialize root for the tree
Node *root;
//intilialize array of 5,000,000 elements, and scores
static int nums[SIZE];
int i; //iterator
//initialize positive and negative numbers for find method
int positive_num, negative_num;
//initilaize timer
clock_t start_for_adding, start_for_finding;
//add elements to the array
evenArrayGen(SIZE, nums);
shuffle(nums);
//set positive number to one of the first 5000 elements
positive_num = nums[3222];
negative_num = 345; //all numbers in num are even so negative need to be odd
root = NULL; //set the root Node to NULL
start_for_adding = clock(); //zero the timer
//now iterate trough all elements in nums array and add each to
//the binary tree
for(i=0; i<SIZE; i++) {
//check if i reached proper value
if (i == 5000 || i == 50000 || i == 500000 || i == (5000000-1)) {
//add the adding time
printf("\nIndex: %d\n", i);
printf("Adding: %.5f\n", (double) clock() - start_for_adding);
start_for_finding = clock(); //zero the timer
//search for positive num
findNode(root, positive_num);
printf("Finding positive: %.5f\n",
(double) clock() - start_for_finding);
start_for_finding = clock(); //zero the timer
//search for negative num
findNode(root, negative_num);
printf("Finding negative: %.5f\n",
(double) clock() - start_for_finding);
start_for_adding = clock(); //reset the timer for adding
}
addNode(&root, nums[i]);
}
return;
}
The times for finding elements are pointing to zero (in both cases)
I'm pretty lost, have no idea where to follow now (the easiest part for my task shows that is the hardest one...)
The resolution of clock is most likely to coarse to measure the time taken by individual calls to your findNode function. Typically the time is measured to perform such a call lots of times and then divide this time by the number of times the call was performed.

Resources