You are on page 1of 7

Data Structure Tree

Tree
Definition of Trees Consists of nodes each node in a tree (except one, the first one called root) has exactly 1 predecessor. each node has at most a particular number of successors. If there is no limit on the number of successors that a node can have, the tree is called a general tree. If there is a maximum number N of successors for a node, then the tree is called an N-ary tree. In particular a binary (2-ary) tree is a tree in which each node has either 0, 1, or 2 successors. The unique node with no predecessor is called the root of the tree. A node with no successors is called a leaf - there will usually be many leaves in a tree. The successors of a node are called its children; the unique predecessor of a node is called its parent. If two nodes have the same parent, they are called brothers or siblings. In a binary tree the two children are called the left and right.

Drawing Trees The root is drawn at the top; below it are its children. An arc connects a node to each of its children: we sometimes draw arrowheads on the arc, but they are optional because the direction parent->child is always top->bottom. Then we continue in the same manner, the children of each node are drawn below the node. For example, here is a binary tree: A

In general, each child of a node is the root of a tree within the big tree. For example, B is the root of a little tree (B,D,E), so is C. These inner trees are called subtrees. The subtrees of a node are the trees whose roots are the children of the node. e.g. the
1

Data Structure Tree

subtrees of A are the subtrees whose roots are B and C. In a binary tree we refer to the left subtree and the right subtree.

Path in a Tree A path is any linear subset of a tree, e.g. A-B-E and C-F are paths. The length of a path could be counted as either the number of nodes on the path, e.g., A-B-E has length 3. There is a unique path from the root to any node. Simple as this property seems, it is extremely important: all our algorithms for processing trees will depend upon it. The depth or level of a node is the length of this path. When you draw a tree, it is very useful if all the nodes in the same level are drawn as a neat horizontal row. The depth or height of a tree is the maximum depth of the nodes in the tree.

Ordered Trees A tree is ordered if there is some significance to the order of the subtrees. For example, consider this tree: Mary

Fred

Nancy

Anne

Jack

Paul

If this is a family tree, there could be no significance to left and right. In this case the tree is unordered, and we could redraw the tree exchanging subtrees without affecting the meaning of the tree. On the other hand, there may be some significance to left and right - maybe the left child is younger than the right... or (as is the case here) maybe the left child has the name that is earlier in the alphabet. Then, the tree is ordered and we are not free to move around the subtrees.

Structural Definition of Binary Trees A binary tree is either empty or it has 3 parts: a value a left subtree
2

Data Structure Tree

a right subtree Whenever a data structure has a recursive definition like this, most of the `properties' of the data structure can be computed in a recursive manner which exactly mirrors the definition. For example, here is a function to compute the number of nodes in a binary tree: int size(binary_tree *t) { return is_empty(t) ? 0 : 1 + size(t->left) + size(t->right); } Note that it is possible to scan through a tree non-recursively, but it is not nearly as easy as scanning recursively. Complete Binary Tree each node has exactly 2 children Full Binary Tree all leave node are at the same level

Tree Traversal Tree Traversal is to process every node in the data structure exactly once. Note that you may pass through a node as many times as you like but you must only process the node once. For example, we can talk about traversing a list, which means going through the list and processing every node once. We had a special name for this: map. For a specific data structure, we talk about the different orders in which it might be traversed. The general recursive pattern for traversing a (non-empty) binary tree is depth first search traversals: At node N you must do these three things: (L) recursively traverse its left subtree. When this step is finished you are back at N again. (R) recursively traverse its right subtree. When this step is finished you are back at N again. (N) Actually process N itself. We may do these things in any order and still have a legitimate traversal. If we do (L) before (R), we call it left-to-right traversal, otherwise we call it right-to-left traversal..
3

Data Structure Tree

Pre-Order Traversal do (N), (L) and then (R) Post-Order Traversal do (L), (R) and then (N) In-Order, or Infix Order, Traversal do (L), (N) and the (R) For example, suppose we were writing out the nodes of the tree in post-order: void print_tree(binary_tree *t) { if (! is_empty(t)) { print_tree(t->left); /* L */ print_tree(t->right); /* R */ printf("%d\n",t->value); /* N */ } } A

The preceding diagrams show us the order in which the nodes will get written: Pre-Order: A-B-D-C-E-F In-Order: B-D-A-E-C-F Post-Order: D-B-E-F-C-A

Breadth First Traversal These three are certainly not the only possible traversal orders. Another very natural traversal order is ``level by level'' - the root is processed first, all its children are processed next, then all of their children, etc. down to the bottom level. This is called breadth first traversal. In the above example, it would process nodes in the order: A-B-C-D-E-F.

Data Structure Tree

Application: Expression Tree Represent expression as a tree Operators are parent nodes to operands Specified order of tree traversal gives method for evaluating expression Example : 1+2 *3 +

2
Inorder Traversal PreOrder Traversal : 1+2*3 : +1*23

PostOrder Traversal : 123*+

C Code of Binary Tree #include <stdio.h> #include <stdlib.h> #include <string.h> /* Tree Node Definition with String Key */ typedef struct node { struct node *left; struct node *right; char key[BUFSIZ]; }node;

Data Structure Tree

/* Non-Recursive Tree Insertion Function */ void tree_insert(node **root, node *new_node) { node *this_node = *root; int dif; while(this_node) { if (! (dif = strcmp(new_node->key, this_node->key))) { strncpy(this_node->key, new_node->key, BUFSIZ); this_node->key[BUFSIZ] = '\0'; return; } else if(dif < 0) { if(this_node->left) this_node = this_node->left; else { this_node->left = (node*) malloc(1, sizeof(node)); this_node = this_node->left; strncpy(this_node->key, new_node->key, BUFSIZ); this_node->key[BUFSIZ] = '\0'; return; } } else { if(this_node->right) this_node = this_node->right; else { this_node->right = (node *) malloc(1, sizeof(node)); this_node = this_node->right; strncpy(this_node->key, new_node->key, BUFSIZ); this_node->key[BUFSIZ] = '\0'; return; } } }

Data Structure Tree

/* only arrives here when instantiating root */ this_node = (node *) malloc(1, sizeof(node)); *root = this_node; strncpy(this_node->key, new_node->key, BUFSIZ); this_node->key[BUFSIZ] = '\0'; } /* Recursive In-Order Traversal */ /* Function Prints Key String */ void tree_trace(node *root) { if(! root) return; tree_trace(root->left); printf("%s\n", root->key); tree_trace(root->right); } /* String Key Tree Main Program */ void main(void) { node *tree_root = NULL; node this_node = { NULL, NULL, "" }; char *str[5] = { "some", "duplicate", "and", "duplicate", "keys" }; int i; for(i = 0;i < 5;i++) { strcpy(this_node.key, str[i]); tree_insert(&tree_root, &this_node); } tree_trace(tree_root); }

You might also like