Monday 18 January 2016

Trees Terminology,binary search tree,Depth First Search,Breadth First Search

Trees & Binary Trees
A tree is a non linear data structure.
A tree consists of nodes connected by edges. The nodes are represented as circles, and the
edges as lines connecting the circles.
There are different kinds of trees: multiway trees, binary trees  etc.

Many terms are used to describe particular aspects of trees. They are:






Path
The sequence of nodes along the edges that connect them is called a path.

Root
The node at the top of the tree is called the root. There is only one root in a tree. In a tree, there must be one (and only one!) path from the root to any other node.

Parent
Any node (except the root) has exactly one edge running upward to another node.
The node above it is called the parent of the node.

Child
Any node may have one or more lines running downward to other nodes. These
nodes below a given node are called its children.

Leaf
A node that has no children is called a leaf node or simply a leaf. There can be only
one root in a tree, but there can be many leaves.

Subtree
Any node may be considered to be the root of a subtree, which consists of its children,
and its children’s children, and so on.

Visiting
A node is visited when program control arrives at the node, usually for the purpose of
carrying out some operation on the node, such as checking the value of one of its
data fields or displaying it.

Traversing
To traverse a tree means to visit all the nodes in some specified order. For example,
we might visit all the nodes in order of ascending key value.

Levels
The level of a particular node refers to how many generations the node is from the
root. If we assume the root is Level 0, then its children will be Level 1, its grandchildren
will be Level 2, and so on.

Keys
In tree diagrams, when a circle represents a node holding a data item, the key value of the
item is typically shown in the circle. This key value is used to search for the item or perform other operations on it.  

Binary Trees
If every node in a tree can have at most two children, the tree is called a binary tree.
The two children of each node in a binary tree are called the left child and the right
Child.


A node in a binary tree may have both the children, only a left child, or only a right child, or it can have no children at all (in which case it’s a leaf).
Binary search tree
Is a kind of binary tree.
The defining characteristic of a binary search tree is: A node’s left child must have a key
less than its parent, and a node’s right child must have a key greater than or equal to its

parent.

The different operations on binary search tree are:
Ø  Inserting a node
Ø  Finding a node
Ø  Deleting a node
Ø  Traversing a tree
Ø  Finding a minimum & maximum value.

Finding a node:
Let the value to be found is the key value say 57.
       We know that the defining characteristic of a binary search tree is: A node’s left child must have a key less than its parent, and a node’s right child must have a key greater than or equal to its parent.





        Finding node starts at the root. The program compares the key value 57
with the value at the root, which is 63. The key is less, so the program knows the
desired node must be on the left side of the tree—either the root’s left child or one of
this child’s descendants. The left child of the root has the value 27, so the comparison
of 57 and 27 will show that the desired node is in the right subtree of 27. The
arrow will go to 51, the root of this subtree. Here, 57 is again greater than the 51
node, so we go to the right, to 58, and then to the left, to 57. This time the comparison
shows 57 equals the node’s key value, so we’ve found the node we want.

Code for the find() function:

public Node find(int  key)                         // find node with given key
   {                                                                  // (assumes non-empty tree)
       Node current = root;                         // start at root
       while(current.iData != key)               // while no match,
            {
               if(key < current.iData)                // go left?
                     current = current.leftChild;
              else
                     current = current.rightChild; // or go right?
               if(current == null)                        // if no child,
                     return null;                            // didn’t find it
           }
       return current; // found it
   }


Inserting a Node :
To insert a node we must first find a place to insert it. This is much the same process as trying to find a node that turns out not to exist. ie;  We follow the path from the root to the appropriate node, which will be the parent of the new node. When this parent is found, the new node is connected as its left or right child, depending on whether the new node’s key is less or greater than that of the parent.



Example:
Let’s assume we’re going to insert a new node with the value 45. The first step for the program in inserting a node is to find where it should be inserted. The value 45 is less than 60 but greater than 40, so we arrive at node 50. Now we want to go left because 45 is less than 50, but 50 has no left child; its leftChild field is null. When it sees this null, the insertion routine has found the place to attach the new node. A new node is created with the value 45 and connects it as the left child of 50.

Code for the insert() function:
public void insert(int id, double dd)
{
    Node newNode = new Node();                // make new node
    newNode.iData = id;                               // insert data
    newNode.dData = dd;
   if(root==null)                                           // no node in root
         root = newNode;
   else // root occupied
       {
          Node current = root;                           // start at root
          Node parent;
         while(true)                                          // (exits internally)
             {
                 parent = current;
                 if(id < current.iData)                   // go left?
                      {
                        current = current.leftChild;
                         if(current == null)                 // if end of the line,
                             {                                        // insert on left
                                parent.leftChild = newNode;
                                return;
                             }
                      }                                                 // end if go left
                 else                                                  // or go right?
                      {
                         current = current.rightChild;
                         if(current == null)                  // if end of the line
                            { // insert on right
                                 parent.rightChild = newNode;
                                 return;
                             }
                       }                                            // end else go right
             }                                                    // end while
    }                                                           // end else not root
}                                                               // end insert()


Deleting a Node

Deleting a node is the most complicated common operation required for binary
search trees.
We start by finding the node we want to delete, using the same approach we saw
in find() and insert(). When we have found the node, there are three cases to
consider:
1. The node to be deleted is a leaf (has no children).
2. The node to be deleted has one child.
3. The node to be deleted has two children.

Case 1: The Node to Be Deleted Has No Children
To delete a leaf node, you simply change the appropriate child field in the nodes
parent to point to null, instead of to the node. The node will still exist, but it will no
longer be part of the tree.



Example:

Assume we are going to delete node 7. The first part of the delete() routine is similar to find() and insert(). It involves finding the node to be deleted. As with insert(), we need to remember the parent of the node to be deleted so we can modify its child fields. If we find the node, we drop out of the while loop with parent containing the node to be deleted. If we can’t find it, we return from delete() with a value of false.

public boolean delete(int key)                         // delete node with given key
{                                                                      // (assumes non-empty list)
    Node current = root;
    Node parent = root;
    boolean isLeftChild = true;
   while(current.iData != key)                          // search for node
            {
                parent = current;
                if(key < current.iData)                    // go left?
                        {
                            isLeftChild = true;
                            current = current.leftChild;
                        }
                else                                                  // or go right?
                        {
                             isLeftChild = false;
                             current = current.rightChild;
                        }
                if(current == null)                           // end of the line,
                        return false;                             // didn’t find it
            }                                                          // end while
                                                            // found node to delete  continues...
}
After weve found the node, we check first to verify that it has no children. When
this is true, we check the special case of the root. If thats the node to be deleted, we
simply set it to null; this empties the tree. Otherwise, we set the parents leftChild or
rightChild field to null to disconnect the parent from the node.

                                                            // delete() continued...
                                                            // if no children, simply delete it
  if(current.leftChild==null && current.rightChild==null)
    {
         if(current == root)                      // if root,
              root = null;                            // tree is empty
        else if(isLeftChild)
              parent.leftChild = null;         // disconnect
        else                                              // from parent
               parent.rightChild = null;
}




Graph Traversal  
The breadth first search (BFS) and the depth first search (DFS) are the two algorithms used for traversing and searching a node in a graph. They can also be used to find out whether a node is reachable from a given node or not.   
Depth First Search (DFS) 
The aim of DFS algorithm is to traverse the graph in such a way that it tries to go far from the root node. Stack is used in the implementation of the depth first search. Let’s see how depth first search works with respect to the following graph:   
As stated before, in DFS, nodes are visited by going through the depth of the tree from the starting node.




 If we do the depth first traversal of the above graph and print the visited node, it will be “A B E F C D”. DFS visits the root node and then its children nodes until it reaches the end node, i.e. E and F nodes, then moves up to the parent nodes. 
Algorithmic Steps   
1.       Step 1: Push the root node in the Stack.  
2.       Step 2: Loop until stack is empty. 
3.       Step 3: Peek the node of the stack.  
4.       Step 4: If the node has unvisited child nodes, get the unvisited child node, mark it as traversed and push it on stack.   
5.       Step 5: If the node does not have any unvisited child nodes, pop the node from the stack.
Based upon the above steps, the following Java code shows the implementation of the DFS algorithm:  
//
public void dfs()
{
               //DFS uses Stack data structure
               Stack s=new Stack();
               s.push(this.rootNode);
               rootNode.visited=true;
               printNode(rootNode);
               while(!s.isEmpty())
               {
                               Node n=(Node)s.peek();
                               Node child=getUnvisitedChildNode(n);
                               if(child!=null)
                               {
                                              child.visited=true;
                                              printNode(child);
                                              s.push(child);
                               }
                               else
                               {
                                              s.pop();
                               }
               }
               //Clear visited property of nodes
               clearNodes();
}

//  
Breadth First Search (BFS)  
This is a very different approach for traversing the graph nodes. The aim of BFS algorithm is to traverse the graph as close as possible to the root node. Queue is used in the implementation of the breadth first search. Let’s see how BFS traversal works with respect to the following graph:
If we do the breadth first traversal of the above graph and print the visited node as the output, it will print the following output. “A B C D E F”. The BFS visits the nodes level by level, so it will start with level 0 which is the root node, and then it moves to the next levels which are B, C and D, then the last levels which are E and F.  
Algorithmic Steps   
1.       Step 1: Push the root node in the Queue.
2.       Step 2: Loop until the queue is empty.
3.       Step 3: Remove the node from the Queue.
4.       Step 4: If the removed node has unvisited child nodes, mark them as visited and insert the unvisited children in the queue.
Based upon the above steps, the following Java code shows the implementation of the BFS algorithm:  
//
public void bfs()
{
               //BFS uses Queue data structure
               Queue q=new LinkedList();
               q.add(this.rootNode);
               printNode(this.rootNode);
               rootNode.visited=true;
               while(!q.isEmpty())
               {
                               Node n=(Node)q.remove();
                               Node child=null;
                               while((child=getUnvisitedChildNode(n))!=null)
                               {
                                              child.visited=true;
                                              printNode(child);
                                              q.add(child);
                               }
               }
               //Clear visited property of nodes
               clearNodes();

}


No comments:

Post a Comment