Section 2 - Binary Search Tree Completed
4B.2.1 Finding a Node
We have actually implemented a find algorithm implicitly in both of our prior methods, insert() and remove(). The recursive step, where we went left or right down the tree, was the basic idea of find. However, we might like a find() that does not actually do anything to the tree other than return the Comparable object found.
Once we have a Comparable find(Comparable &x) that returns the object found, we can add a trivial encapsulation of it viz-a-viz a bool contains(Comparable &x) which returns a bool (true or false), stating whether or not x is in the tree. Often, contains() is all we need.
considering an int tree, find() seems superfluous. After all, why not just provide contains()? If I want to know if 6 is in the tree, and contains(6) tells me, "yes it is", why do I need the actual "found 6"? I have the "searched-for 6" already, and both 6s are identical. The answer to this question has to do with non-primitive data. Normally, we have a tree that contains user-defined objects, and we are looking for an object that has a particular search key (say a social security number). What we want, then, is the entire object (the Employee or iTunesEntry) because that has other information we will need to look a
The actual use of this find() will require first building an empty object around the search key, and then passing that object to find(). find() will then return the one that was in the tree with the same search key.
As usual, find() is a pair of public/private overloads. here is the public one:
template <class Comparable> const Comparable &FHsearch_tree<Comparable>::find( const Comparable &x) const { FHs_treeNode<Comparable> *resultNode; resultNode = find(mRoot, x); if (resultNode == NULL) throw NotFoundException(); return resultNode->data; }
As you see, we are going to throw an exception if the object is not found, since otherwise we would have to decide on some sort of default "not-found" object to return. That's not to say we could not do it: we might have returned the same object passed in from the client in the case of a not-found condition, and let the client test the returned object to see if it was the same as what it passed in (not-found) or different (found). But this is too demanding. A simple try/catch can be used by the client to do the same thing. NotFoundException() is a bare user-defined exception in our FHsearch_tree class.
Now the private version:
template <class Comparable> FHs_treeNode<Comparable>* FHsearch_tree<Comparable>::find( FHs_treeNode<Comparable> *root, const Comparable &x) const { if (root == NULL) return NULL; if (x < root->data) return find(root->lftChild, x); if (root->data < x) return find(root->rtChild, x); return root; }
By now you should be getting very comfortable with this same recursion which we have seen five or six times.
As promised, we have our trivial contains() that uses the private find():
bool contains(const Comparable &x) const { return find(mRoot, x) != NULL; }