# Trees for Storage and Search

Dr. Lawlor, CS 202, CS, UAF

Like linked lists, trees are a recursively defined data structure.  Here's a linked list, with recursive traversal and construction functions:
`class llnode {public:	int data;	llnode *next;	llnode(int v,llnode *n) {data=v; next=n;}};int total(llnode *cur,int sum){	if (cur==0) { return sum; } // base case	else { return total(cur->next,cur->data + sum); }}llnode *make_list(void) {	int x;	if (cin>>x) { return new llnode(x,make_list()); }	else { return NULL; }}int foo(void) {	llnode *cur=make_list();	return total(cur,0);}`

(Try this in NetRun now!)

Here's a tree.  It's like a linked list with *two* next pointers, called "child pointers".  One child is the left subtree, and the other is the right subtree.  One or both of the "child" pointers might be NULL.  Because you've got two children, this is called a "binary tree"; if you've got four children (for example, "topleft", "topright", "bottomleft", and "bottomright"), it'd be a "4-ary tree".  To traverse the tree, you just need to recurse down both the left and the right subtrees.
`class treenode {public:	int data;	treenode *left;	treenode *right;	treenode(int v,treenode *l,treenode *r) {data=v; left=l; right=r;}};int total(treenode *cur){	if (cur==0) { return 0; } // base case	else { return cur->data + total(cur->left) + total(cur->right); }}treenode *make_tree(void) {	int x;	if (cin>>x && x>=0) { 		treenode *left=make_tree();		treenode *right=make_tree();		return new treenode(x,left,right); 	}	else { return NULL; }}int foo(void) {	treenode *cur=make_tree();	return total(cur);}`

(Try this in NetRun now!)

This program is a little weird, because you need to give the input data (cin>>x) in a very particular order--in a preorder traversal of the tree.

A more common way to build and look up trees is by ordering the children--for example, we can store values greater than ours in our right child; and values smaller than ours in the left child.  This way of building the tree makes it much more efficient to look up values--rather than look at both children, we can compare the value to ours, and know exactly where to look.  This is called a "binary search tree".  Here's a more detailed explanation of how to build a binary search tree
`class treenode {public:	int data;	treenode *left; // values < than data	treenode *right; // values > than data	treenode(int v,treenode *l,treenode *r) {data=v; left=l; right=r;}};// Return the treenode containing this valuetreenode *lookup(treenode *cur,int value){	if (cur==0) { return NULL; } // base case (not found)	else { 		if (value<cur->data) return lookup(cur->left,value);		else if (value>cur->data) return lookup(cur->right,value);		else /* value==cur->data */ return cur;	}}void printtree(treenode *cur,int level){	if (cur==0) return;	printtree(cur->left,level+1);	for (int i=0;i<level;i++) cout<<"  ";	cout<<cur->data<<"\n";	printtree(cur->right,level+1);}void add_to_tree(int x,treenode *&cur) {	if (cur==0) cur=new treenode(x,0,0);	else if (x<cur->data) add_to_tree(x,cur->left);	else if (x>cur->data) add_to_tree(x,cur->right);	else /* x==cur->data */ {		std::cout<<"Error! Duplicate value "<<x<<" in tree!\n";		exit(1);	}}treenode *make_tree(void) {	treenode *cur=0;	int x;	while (cin>>x) add_to_tree(x,cur);	return cur;}int foo(void) {	treenode *cur=make_tree();	printtree(cur,0);	treenode *v7=lookup(cur,7);	treenode *v9=lookup(cur,9);	std::cout<<"found 7 at "<<v7<<" and 9 at "<<v9<<"\n";	return 0;}`

(Try this in NetRun now!)

You can even extract a range of values, which come out sorted for free.
`class treenode {public:	int data;	treenode *left;	treenode *right;	treenode(int v,treenode *l,treenode *r) {data=v; left=l; right=r;}};int total(treenode *cur){	if (cur==0) { return 0; } // base case	else { return cur->data+total(cur->left)+total(cur->right); }}treenode *make_tree(void) {	int x;	if (cin>>x && x>=0) { return new treenode(x,make_tree(),make_tree()); }	else { return NULL; }}void print_tree(treenode *cur,int level) {	if (cur==NULL) return;	for (int i=0;i<level;i++) cout<<"  ";	cout<<cur->data<<"\n";	print_tree(cur->left,level+1);	print_tree(cur->right,level+1);}treenode *find(treenode *cur,int value) {	if (cur==NULL) return NULL; // base case: not found	if (value<cur->data) return find(cur->left,value);	if (value>cur->data) return find(cur->right,value);	return cur;}void print_range(treenode *cur,int lo,int hi) {	if (cur==NULL) {return;} // base case: not found	if (lo<cur->data) print_range(cur->left,lo,hi);	if (lo<=cur->data && cur->data<hi) cout<<" found at "<<cur->data<<"\n";	if (hi>cur->data) print_range(cur->right,lo,hi);}int foo(void) {	treenode *cur=make_tree();	print_tree(cur,0);	for (int value=0;value<10;value++) cout<<"Tree has "<<value<<" at "<<find(cur,value)<<"\n";	print_range(cur,-10000000,1000000000);	return total(cur);}`

(Try this in NetRun now!)

Trees come up again and again in computer science--searching is often much faster in a tree!