Improving this binary tree algorithm complexity - algorithm

I need to find if all paths of a binary tree that can end(which means all paths that starts from the root and end to a node that has only one child or none) have lengths that differ by no more than one.
My working solution work like this: the function longestPath finds the longest path, the function checkLengths traverse all nodes keeping track of the length of the paths and every time a node with only one child or none is found it checks if the difference between the length of the current path and the length of the longest path is more than 1.
This solution has complexity O(2n) because at worst every node has to be visited twice, once for the longestPath function and once for the lengthCheck function. I would like to improve the solution to O(n) but I'm having an hard time figuring out how to do so.
Edit: my solution is still O(n) but I would like to optimize it to find the solution by visiting each node only once and not twice.
int lengthCheckFlag=1;
int maxLength=-1;
void longestPath(Node n,int currentLength){
if(n==nullptr){
return;
}
if(n->left==nullptr && n->right==nullptr){
if(maxLength==-1){
maxLength=currentLength;
}
else{
if(currentLength>maxLength){
maxLength=currentLength;
}
}
}
longestPath(n->left,currentLength+1);
longestPath(n->right,currentLength+1);
}
void checkLengths(Node n,int currentLength){
if(n==nullptr){
return;
}
if(n->left==nullptr || n->right==nullptr){
if(abs(maxLength-currentLength)>1){
lengthCheckFlag=0;
}
}
checkLengths(n->left,currentLength+1);
checkLengths(n->right,currentLength+1);
}
bool lengthCheckWrapper(Node n){
if(n==nullptr){
return true;
}
longestPath(n,0);
checkLengths(n,0);
return lengthCheckFlag;
}
Code Update:
int maxP=-1;
int minP=-1;
void minmaxPaths(Node n,int currentLength){
if(n==nullptr){
return;
}
if(n->left==nullptr && n->right==nullptr){
if(maxP==-1){
maxP=currentLength;
minP=currentLength;
}
else{
if(currentLength>maxP){
maxP=currentLength;
}
if(currentLength<minP){
minP=currentLength;
}
}
}
minmaxPaths(n->left,currentLength+1);
minmaxPaths(n->right,currentLength+1);
}
bool lengthCheckWrapper(Node n){
if(n==nullptr){
return true;
}
minmaxPaths(n,0);
if(abs(minP-maxP)<=1){
return true;
}
return false;
}

Some remarks:
O(2n) is the same as O(n)
Your functions use different conditions for identifying the potential end of a path: one uses a && operator (wrong) and the other uses a || operator (correct)
One idea for an alternative algorithm is to make a breadth first traveral. This is interesting, since the constraint really means that all non-perfect nodes (i.e. that have at most one child) must appear in the bottom two levels of the tree.
By consequence, if we find 2 more levels after the first level where we find a non-perfect node, then we have a violation and can stop the traversal.
The down side is that it uses more memory.
Here is how it could be implemented:
int minmaxDepth(Node root) {
if (root == nullptr) {
return 1; // OK
}
std::vector<Node> level, nextLevel;
level.push_back(root);
int minDepth = INT_MAX;
int currDepth = 0;
while (level.size()) {
currDepth++;
nextLevel = {};
for (auto & parent : level) {
if (currDepth < minDepth &&
(parent->left == nullptr || parent->right == nullptr)) {
minDepth = currDepth; // Found a path with minimal length
}
if (parent->left != nullptr) {
nextLevel.push_back(parent->left);
}
if (parent->right != nullptr) {
nextLevel.push_back(parent->right);
}
if (nextLevel.size() && currDepth > minDepth) {
return 0; // Paths have lengths that differ more than 1
}
}
level = nextLevel;
}
return 1; // All nodes were visited: no violation found
}

There is no need to pre-compute the longest path. Compute all path lengths and on the fly,
store the first length,
if some other length differs by more than one, you are done;
else store the differing length, and if any other length differs from the two stored ones, you are done.

Related

Find kth min node in AVL tree

I now have built a AVL tree, Here is a function to find kth min node in AVL tree
(k started from 0)
Code:
int kthMin(int k)
{
int input=k+1;
int count=0;
return KthElement(root,count,input);
}
int KthElement( IAVLTreeNode * root, int count, int k)
{
if( root)
{
KthElement(root->getLeft(), count,k);
count ++;
if( count == k)
return root->getKey();
KthElement(root->getRight(),count,k);
}
return NULL;
}
It can find some of right nodes, but some may fail, anyone can help me debug this>
THanks
From the root, after recursing left, count will be 1, regardless of how many nodes are on the left.
You need to change count in the recursive calls, so change count to be passed by reference (assuming this is C++).
int KthElement( IAVLTreeNode * root, int &count, int k)
(I don't think any other code changes are required to get pass by reference to work here).
And beyond that you need to actually return the value generated in the recursive call, i.e. change:
KthElement(root->getLeft(), count, k);
to:
int val = KthElement(root->getLeft(), count, k);
if (val != 0)
return val;
And similarly for getRight.
Note I used 0, not NULL. NULL is typically used to refer to a null pointer, and it converts to a 0 int (the latter is preferred when using int).
This of course assumes that 0 isn't a valid node in your tree (otherwise your code won't work). If it is, you'll need to find another value to use, or a pointer to the node instead (in which case you can use NULL to indicate not found).
Here is simple algorithm for Kth smallest node in any tree in general:-
count=0, found=false;
kthElement(Node p,int k) {
if(p==NULL)
return -1
else {
value = kthElement(p.left)
if(found)
return value
count++
if(count==k) {
found = true
return p.value
}
value = kthElement(p.right)
return value
}
}
Note:- Use of global variables is the key.

PreOrder Successor of a Node in BST

I'm trying this question for sometime but couldn't figure out the algorithm. My preference is to do it iteratively. Till now, I've figure out something but not sure on some point.
Currently, My algorithm looks like:
First traverse the tree to find the node
While traversing the tree, keep track of the previous node.
if you find the node, check if left child is present then that is successor return.
if left child is not present then check if right child is present the that is successor and return.
if the node(is left to the parent) and don't have left or right child then we've saved the prev node earlier then either prev or prev's right child is the successor.
But what if the node we found is in the right to parent and don't have left or right child how to find successor of this node?
May be there are many flaws in this algorithm as still I've not understand all the cases properly. If anyone has any idea or algorithm please share.
Thanks in advance.
when you find a node in preorder, to find its successor is just travesing to its next node.
what I was thinking first is the relationship of a node and its successor's values in pre-oder, but I found that it seems not very clear like the relationship in in-order. I think there is only one step beteen a node and its successor(if exists) : just move on travesing. So I design this algorithm.
my algorithm below is based on preorder travesal, it can run on a binary tree,not only BST.
#define NOT_FOUND -1
#define NEXT 0
#define FOUND 1
struct node {
struct node *p;//parent,but useless here
struct node *l;//left child
struct node *r;//right child
int value;
};
int travese(struct node* bnode, int* flag,int value)
{
if(bnode == NULL)
return 0;
else
{
if(*flag == FOUND)
//when the successor is found,do pruning.
return 1;
else if(*flag == NEXT) {
printf("successor:%d\n",bnode->value);
*flag = FOUND;
return 1;
}
else if(*flag == NOT_FOUND && bnode->value == value)
*flag = NEXT;
travese(bnode->l,flag,value);
travese(bnode->r,flag,value);
}
return 0;
}
and use it by:
int flag = NOT_FOUND;
travese(root,&flag,value);
if(flag == NEXT || flag == NOT_FOUND)
printf("no successor.\n");
EDIT:
turning a recurrence algorithm to a iterative one is not difficult by using a stack like below:
int preorder_travese_with_stack(struct node* bnode, int* flag,int value)
{
if(bnode == NULL)
return 0;
struct stack s;//some kind of implement
push(s,bnode);
while(NotEmpty(s) && *flag) {
struct node *curNode = pop(s);
if(*flag == NEXT) {
printf("successor:%d\n",curNode->value);
*flag = FOUND;
return 1;
}
else if(*flag == NOT_FOUND && curNode->value == value)
*flag = NEXT;
push(s,curNode->r);
push(s,curNode->l);
}
return 0;
}
but according to your comment and original description, I think the one you want is iterative algorithm without a stack.here it is.
After thinking ,searching and trying, I wrote one. When travse the tree iteratively without stack , the parent of a node is not useless any more. In a path, some nodes is visited not only once, and you need to record its direction at that time.
int preorder_travese_without_stack(struct node *root,int value,int *flag)
{
int state=1;
//state: traveral direction on a node
//1 for going down
//2 for going up from its left chlid
//3 for going up from its right child
struct node *cur = root;
while(1) {
if(state == 1) //first visit
{
//common travese:
//printf("%d ",cur->value);
if(cur->value == value && *flag == NOT_FOUND)
*flag = NEXT;
else if (*flag==NEXT) {
*flag = FOUND;
printf("successor:%d\n",cur->value);
break;
}
}
if((state == 1)&&(cur->l!=NULL))
cur = cur->l;
else if((state==1)&&(cur->l==NULL))
{
state = 2;
continue;
}
else if(state==2) {
if(cur->r != NULL ) {
cur=cur->r;
state = 1;
}
else
{
if(cur->p!=NULL)
{
if(cur==cur->p->r)
state = 3;
//else state keeps 2
cur=cur->p;
}
else //cur->p==NULL
{
if(cur->p->r!=NULL)
{
cur=cur->p->r;
state = 1;
}
else
break;
//end up in lchild of root
//because root's rchild is NULL
}
}
continue;
}
else //state ==3
{
if(cur->p!=NULL)
{
if(cur==cur->p->l)
state = 2;
else
state = 3;
cur=cur->p;
continue;
}
else
break;
}
}
}
the usage is the same as the first recurrence one.
If you are confused yet,mostly about the direction of a node , you can draw a tree and draw the path of pre-order traverse on paper,it would help.
I'm not sure there are bugs left in the code,but it works well on the tree below:
0
/ \
1 2
/ \ / \
3 4 5 6
btw,"wirte down pre-order (or else) travese algorithm of a tree both by recurrence and iteration" is a common interview problem, although solving the latter by a stack is permitted.but I think the BST requirement is unnecessary in pre-order travese.
My implementation of the algorithm does not use the key. Therefore it is possible to use it in any kind of binary tree, not only in Binary search trees.
The algorith I used is this:
if given node is not present, return NULL
if node has left child, return left child
if node has right child, return right child
return right child of the closest ancestor whose right child is present and not yet processed
Bellow there is my solution.
TreeNode<ItemType>* CBinaryTree<ItemType>::succesorPreOrder(TreeNode<ItemType> *wStartNode)
{
//if given node is not present, return NULL
if (wStartNode == NULL) return NULL;
/* if node has left child, return left child */
if (wStartNode->left != NULL) return wStartNode->left;
/* if node has right child, return right child */
if (wStartNode->right != NULL) return wStartNode->right;
/* if node isLeaf
return right child of the closest ancestor whose right child is present and not yet processed*/
if (isLeaf(wStartNode)) {
TreeNode<ItemType> *cur = wStartNode;
TreeNode<ItemType> *y = wStartNode->parent;
while (y->right == NULL && y->parent!=NULL){
cur = y;
y = y->parent;
}
while (y != NULL && cur == y->right) {
cur = y;
y = y->parent;
}
return y->right;
}
}
bool CBinaryTree<ItemType>::isLeaf(TreeNode<ItemType> *wStartNode){
if (wStartNode->left == NULL && wStartNode->right == NULL) return true;
else return false;
};

traverse all edges and print nodes in euler circuit

I am trying to solve this question.
I am able to find by seeing the degrees that the given structure can form euler circuit or not but I am unable to figure out how to find trace all path, for the given test case
5
2 1
2 2
3 4
3 1
2 4
there is one loop in the circuit at node 2, which I don't know how to trace, If I am using adjacency list representation then I'll get following list
1: 2,3
2: 1,2,2,4
3: 1,4
4: 2,3
So how to traverse every edge, I know it is euler circuit problem, but that self loop thing is making tough for me to code and I am not getting any tutorial or blog from where I can understand this thing.
I again thought to delete the nodes from adjacency list once I traverse that path( in order to maintain the property of euler(path should be traversed once)), but I am using vector for storing adjacency list and I don't know how to delete particular element from vector. I googled it and found remove command to delete from vectors but remove deletes all matching element from the vector.
I tried to solve the problem as below now, but getting WA :(
#include<iostream>
#include<cstdio>
#include<cstring>
int G[52][52];
int visited[52],n;
void printadj() {
int i,j;
for(i=0;i<51;i++) {
for(j=0;j<51;j++)
printf("%d ",G[i][j]);
printf("\n");
}
}
void dfs(int u){
int v;
for(v=0;v<51;v++){
if(G[u][v]){
G[u][v]--;
G[v][u]--;
printf("%d %d\n",u,v);
dfs(v);
}
}
}
bool is_euler(){
int i,j,colsum=0,count=0;
for(i=0;i<51;i++) {
colsum=0;
for(j=0;j<51;j++) {
if(G[i][j] > 0) {
colsum+=G[i][j];
}
}
if(colsum%2!=0) count++;
}
// printf("\ncount=%d\n",count);
if(count >0 ) return false;
else return true;
}
void reset(){
int i,j;
for(i=0;i<51;i++)
for(j=0;j<51;j++)
G[i][j]=0;
}
int main(){
int u,v,i,t,k;
scanf("%d",&t);
for(k=0;k<t;k++) {
scanf("%d",&n);
reset();
for(i=0;i<n;i++){
scanf("%d%d",&u,&v);
G[u][v]++;
G[v][u]++;
}
// printadj();
printf("Case #%d\n",k+1);
if(is_euler()) {
dfs(u);
}
else printf("some beads may be lost\n");
printf("\n");
}
return 0;
}
Dont know why getting WA :(
New Code:-
#include<iostream>
#include<cstdio>
#include<cstring>
#define max 51
int G[max][max],print_u[max],print_v[max],nodes_traversed[max],nodes_found[max];
int n,m;
void printadj() {
int i,j;
for(i=0;i<max;i++) {
for(j=0;j<max;j++)
printf("%d ",G[i][j]);
printf("\n");
}
}
void dfs(int u){
int v;
for(v=0;v<50;v++){
if(G[u][v]){
G[u][v]--;
G[v][u]--;
print_u[m]=u;
print_v[m]=v;
m++;
dfs(v);
}
}
nodes_traversed[u]=1;
}
bool is_evendeg(){
int i,j,colsum=0,count=0;
for(i=0;i<50;i++) {
colsum=0;
for(j=0;j<50;j++) {
if(G[i][j] > 0) {
colsum+=G[i][j];
}
}
if(colsum&1) return false;
}
return true;
}
int count_vertices(int nodes[]){
int i,count=0;
for(i=0;i<51;i++) if(nodes[i]==1) count++;
return count;
}
void reset(){
int i,j;
m=0;
for(i=0;i<max;i++)
for(j=0;j<max;j++)
G[i][j]=0;
memset(print_u,0,sizeof(print_u));
memset(print_v,0,sizeof(print_v));
memset(nodes_traversed,0,sizeof(nodes_traversed));
memset(nodes_found,0,sizeof(nodes_found));
}
bool is_connected(int tot_nodes,int trav_nodes) {
if(tot_nodes == trav_nodes) return true;
else return false;
}
int main(){
int u,v,i,t,k,tot_nodes,trav_nodes;
scanf("%d",&t);
for(k=0;k<t;k++) {
scanf("%d",&n);
reset();
for(i=0;i<n;i++){
scanf("%d%d",&u,&v);
G[u][v]++;
G[v][u]++;
nodes_found[u]=nodes_found[v]=1;
}
// printadj();
printf("Case #%d\n",k+1);
tot_nodes=count_vertices(nodes_found);
if(is_evendeg()) {
dfs(u);
trav_nodes=count_vertices(nodes_traversed);
if(is_connected(tot_nodes,trav_nodes)) {
for(i=0;i<m;i++)
printf("%d %d\n",print_u[i],print_v[i]);
}
else printf("some beads may be lost\n");
}
else printf("some beads may be lost\n");
printf("\n");
}
return 0;
}
This code is giving me runtime error there, please look into the code.
What you need to do is form arbitrary cycles and then connect all cycles together. You seem to be doing only one depth first traversal, which might give you a Eulerian circuit, but it also may give you a 'shortcut' of an Eulerian circuit. That is because in every vertex where the Eulerian circuit passes more then once (i.e., where it crosses itself), when the depth first traversal arrives there for the first time, it may pick the edge that leads directly back to the start of the depth first traversal.
Thus, you're algorithm should consist of two parts:
Find all cycles
Connect the cycles together
If done right, you don't even have to check that all vertices have an even degree, instead you can rely on the fact that if step 1 or 2 cannot continue anymore, there exists no Eulerian cycle.
Reference Implementation (Java)
Since there's no language tag in your question, I'm going to assume that it's fine for you that I'll give you a Java reference implementation. Furthermore, I'll use the term 'node' instead of 'vertex', but that's just personal preference (it gives shorter code ;)).
I'll use one constant in this algorithm, which I will refer to from the other classes:
public static final int NUMBER_OF_NODES = 50;
Then, we'll need an Edge class to easily construct our cycles, which are basically linked lists of edges:
public class Edge
{
int u, v;
Edge prev, next;
public Edge(int u, int v)
{
this.u = u;
this.v = v;
}
/**
* Attaches a new edge to this edge, leading to the given node
* and returns the newly created Edge. The node where the
* attached edge starts doesn't need to be given, as it will
* always be the node where this edge ends.
*
* #param node The node where the attached edge ends.
*/
public Edge attach(int node)
{
next = new Edge(this.v, node);
next.prev = this;
return next;
}
}
Then, we'll need a Cycle class that can easily join two cycles:
public class Cycle
{
Edge start;
boolean[] used = new boolean[NUMBER_OF_NODES+1];
public Cycle(Edge start)
{
// Store the cycle itself
this.start = start;
// And memorize which nodes are being used in this cycle
used[start.u] = true;
for (Edge e = start.next; e != start; e = e.next)
used[e.u] = true;
}
/**
* Checks if this cycle can join with the given cycle. That is
* the case if and only if both cycles use a common node.
*
* #return {#code true} if this and that cycle can be joined,
* {#code false} otherwise.
*/
public boolean canJoin(Cycle that)
{
// Find a commonly used node
for (int node = 1; node <= NUMBER_OF_NODES; node++)
if (this.used[node] && that.used[node])
return true;
return false;
}
/**
* Joins the given cycle to this cycle. Both cycles will be broken
* at a common node and the paths will then be connected to each
* other. The given cycle should not be used after this call, as the
* list of used nodes is most probably invalidated, only this cycle
* will be updated and remains valid.
*
* #param that The cycle to be joined to this cycle.
*/
public void join(Cycle that)
{
// Find the node where we'll join the two cycles
int junction = 1;
while (!this.used[junction] || !that.used[junction])
junction++;
// Find the join place in this cycle
Edge joinAfterEdge = this.start;
while (joinAfterEdge.v != junction)
joinAfterEdge = joinAfterEdge.next;
// Find the join place in that cycle
Edge joinBeforeEdge = that.start;
while (joinBeforeEdge.u != junction)
joinBeforeEdge = joinBeforeEdge.next;
// Connect them together
joinAfterEdge.next.prev = joinBeforeEdge.prev;
joinBeforeEdge.prev.next = joinAfterEdge.next;
joinAfterEdge.next = joinBeforeEdge;
joinBeforeEdge.prev = joinAfterEdge;
// Update the used nodes
for (int node = 1; node <= NUMBER_OF_NODES; node++)
this.used[node] |= that.used[node];
}
#Override
public String toString()
{
StringBuilder s = new StringBuilder();
s.append(start.u).append(" ").append(start.v);
for (Edge curr = start.next; curr != start; curr = curr.next)
s.append("\n").append(curr.u).append(" ").append(curr.v);
return s.toString();
}
}
Now our utility classes are in place, we can write the actual algorithm (although technically, part of the algorithm is extending a path (Edge.attach(int node)) and joining two cycles (Cycle.join(Cycle that)).
/**
* #param edges A variant of an adjacency matrix: the number in edges[i][j]
* indicates how many links there are between node i and node j. Note
* that this means that every edge contributes two times in this
* matrix: one time from i to j and one time from j to i. This is
* also true in the case of a loop: the link still contributes in two
* ways, from i to j and from j to i, even though i == j.
*/
public static Cycle solve(int[][] edges)
{
Deque<Cycle> cycles = new LinkedList<Cycle>();
// First, find a place where we can start a new cycle
for (int u = 1; u <= NUMBER_OF_NODES; u++)
for (int v = 1; v <= NUMBER_OF_NODES; v++)
if (edges[u][v] > 0)
{
// The new cycle starts at the edge from u to v
Edge first, last = first = new Edge(u, v);
edges[last.u][last.v]--;
edges[last.v][last.u]--;
int curr = last.v;
// Extend the list of edges until we're back at the start
search: while (curr != u)
{
// Find any edge that extends the last edge
for (int next = 1; next <= NUMBER_OF_NODES; next++)
if (edges[curr][next] > 0)
{
// We found an edge, attach it to the last one
last = last.attach(next);
edges[last.u][last.v]--;
edges[last.v][last.u]--;
curr = next;
continue search;
}
// We can't form a cycle anymore, which
// means there is no Eulerian cycle.
return null;
}
// Connect the end to the start
last.next = first;
first.prev = last;
// Save it
cycles.add(new Cycle(last));
// And don't forget about the possibility that there are
// more edges running from u to v, so v should be
// re-examined in the next iteration.
v--;
}
// Now we have put all edges into cycles,
// we join them all together (if possible)
merge: while (cycles.size() > 1)
{
// Join the last cycle with any of the previous ones
Cycle last = cycles.removeLast();
for (Cycle curr : cycles)
if (curr.canJoin(last))
{
// Found one! Just join it and continue the merge
curr.join(last);
continue merge;
}
// No compatible cycle found, meaning there is no Eulerian cycle
return null;
}
return cycles.getFirst();
}

Sum of depth of all nodes in binary tree (Path length)

I am trying to implement a function to calculate path length of a binary tree and i am not able to get the correct answer. Can you check what i am doing wrong? Here is my code below:
public int pathLength() {
int sum = 0;
int c = 1;
pathLength(root, sum);
return sum;
}
public int pathLength(Node n, int sum) {
if(n.isRoot())
sum+= 0;
if(n.left == null && n.right == null)
return;
c++;
if(n.left != null)
sum += c;
if (n.right != null)
sum+=c;
pathLength(n.left, sum);
pathLength(n.right, sum);
}
There are a lot of things wrong with this code. It wouldn't even compile because a) In the 2nd function c is never declared (it is local in the first) and b) the 2nd function never returns a value.
But the biggest issue is the way you declare the 2nd function. "sum" is passed by value. That basically means a new copy of "sum" is created each time you call the function and is discarded when the function ends.
What you want to do is pass by reference. When doing this, the actual sum variable, not a copy, is passed to the function. So your code might look like this:
public void pathLength(Node n, int& sum) {
//if(n.isRoot()) <- not sure what this is for
// sum+= 0;
sum += 1; // Increment for this node
//if(n.left == null && n.right == null)
// return; // This conditional is not needed with next 2 if statements
//c++; <- Don't know what c is for
// Recursively call for child nodes
if(n.left != null)
pathLength(n.left, sum);
if (n.right != null)
pathLength(n.right, sum);
}
Note that this counts all the nodes in the tree. I assume that's what you want. If you want to find the deepest node, that's different.
Is it because of you set the initial value of c as 1 instead of 0?
The children of root should be at level 2 with the depth 1.
Here is an easy approach
Time : O(n) while the space will be O(h) where h is the height of the binary tree:
int sum(BinaryTree *node, int count){
if(node == nullptr){
return 0;
}
return count + sum(node->left, count+1)+sum(node->right, count+1);
}
int nodeDepths(BinaryTree *root) {
int count=0;
int ans=0;
ans =sum(root, count);
return ans;
}

searching a binary tree

I'm writing an iterative function to search a binary tree for a certain value. This is localized to signed ints until I get into how to genericize classes.
Assume that my class is BinarySearchTree, and it has a pointer to the root node of the tree. Also assume that nodes are inserted through an insert function, and have pointers to two children. Here is a much abbreviated version of the Node struct:
struct Node
{
public:
Node *left_, *right_;
int value_
Node(int val) : value_(val), left_(0), right_(0) { }
//done in this manner to always make sure blank children are
//init to zero, or null
Node(int val, Node *left, Node *right) : value_(val), left_(0), right_(0)
{ left_ = left; right_ = right; }
}
So, you can safely assume that a node's uninit pointers will be NULL.
Here is my code:
int BinarySearchTree::search(int val)
{
Node* next = this->root();
while (next->left() != 0 || next->right () != 0)
{
if (val == next->value())
{
return next->value();
}
else if (val < next->value())
{
next = next->left();
}
else if (val > next->value())
{
next = next->right();
}
}
//not found
return 0;
}
This code is being rejected by a friend for two reasons:
1) If next has no children, both will evaluate to zero and I will prematurely exit the loop (I will never check the searched val against next's value).
2) If next has one child, but the data you are searching for should be on the empty side of the tree, next will be set to 0, and it will loop again, comparing next (which is 0) to the left and right trees like while(0->left()), resulting in undefined behavior.
I am told that the solution to both problems lies in the loop condition, but I can't see what I can do to easily remedy the situation. Can the community of Stack Overflow offer any insights?
I think you should be testing if next is not NULL in your loop like so:
int BinarySearchTree::search(int val)
{
Node* next = this->root();
while (next)
{
if (val == next->value())
{
return next->value();
}
else if (val < next->value())
{
next = next->left();
}
else if (val > next->value())
{
next = next->right();
}
}
//not found
return 0;
}
Try this:
while (next != NULL) ?
First of all, I'm not sure why you are returning an int. What if you are searching for 0 in the tree. You probably want something like this:
bool BinarySearchTree::Search(int val) {
Node* current = root();
while (current != NULL) {
// Check if it's here
if (val == current->value()) {
return true;
}
if (val < current->value()) {
current = current->left();
} else {
current = current->right();
}
}
// Not found
return false;
}
Notice that the loop invariant: at the beginning of each loop, you are at a non null node that you need to "process". First check if it's the node you want. If not, make a branch, and let the loop decide if the branch was "good" (ie - non null). Then you'll let the next loop iteration take care of testing.

Resources