< Prev PageHome
1.1 Uninformed Searches
The SimpleTreeSearch class defined below in Listing 1-3 below contains two Depth First Search methods and one Breadth First Search.  Each method takes a starting node and target node for its arguments and its node tree from _nList which was instanced in the parent class AbsTreeSearch and populated in BuildAdjacencyList ( ) which must be overridden in the SimpleTreeSearch class definition.  The base method's constructor is called in SimleTreeSearch's constructor.  This is not strictly necessary (the base constructor is called by default), but included here as a reminder that an argument can be passed to the constructor at this point.  For instance, in a large application, the base constructor might test available space before creating an instance of the node list.  The number of nodes could be passed back to the base here.   

In DFS ( ), a non-recursive DFS method, the starting node is pushed onto a Last In First Out (LIFO) stack.  The search proceeds down each limb of the tree marking each node as visisted.   A node's neighbors are pushed onto the stack.  If a node has been visited, it is not examined and execution continues in a new iteration of the while-loop.  Otherwise, nodes are popped from the stack one at a time and their neighbors are pushed onto the stack, and so forth.  The search ends either when a node is found to be the goal node, or _nList has been exhausted.  Note that _nList does not explicitly appear in the DFS ( ) method.  However, all the nodes in the list will be tested (until a goal node is found) because the neighbors of the starting node are tested, and each of their neighbors are tested until all nodes and their neighbors have been examined.

The second DFS method DFS_Recursive ( )  replaces the stack with a recursive call to itself.  While execution proceeds down each branch of the stack, the sequence of examined nodes differs from the non-recursive variation.  In the non-recursive case, popped nodes are examined in the reverse order that they were pushed onto the stack.  

BFS ( ), a Breadth First Search uses a First In First Out (FIFO) queue to order nodes to be examined.  All the nodes at a specific level or distance, say d, from the starting node are examined before proceeding further. 

A demonstration program which combines the three previous listings with the node tree shown on the previous page can be run as shown in the skeletal listing on the next page.  The accompanying figure shows the resulting console output.  
Listing 1-3 CLASS SimpleTreeSearch DEFINITION    (Show Code ...)

Listing 1-3 Simple Tree-Search Implementation with Depth First and Breadth First Searches  
     public class SimpleTreeSearch : AbsTreeSearch
     {
         Stack<Node> _nodes;
   
         public SimpleTreeSearch(int noOfNodes) : base()
         {
              _nodes = new Stack<Node>();
              BuildAdjacencyList ()
         }
  
         public void DFS(Node start, Node goal)
         {
             _nodes.Push(start);
             while (_nodes.Count > 0)
             {
                 Node node = _nodes.Pop();
                 if (node.Visited)
                     continue;
                 else
                     node.Visited = true;
                 Console.WriteLine("Visiting " + node.NodeValue.ToString());
              
                 if (node == goal)
                 {
                     Console.WriteLine("DFS found goal node.\n");
                     return;
                 }
  
                 for (int i = 0; i < node.NeighborNodes.Count; i++)
                     _nodes.Push(node.NeighborNodes[i]);
             }
 
             Console.WriteLine("DFS did not find goal node.\n");
         }
 
         public bool DFS_Recursive(Node start, Node goal)
         {
             if ((start != goal) && (!start.Visited))
             {
                 Console.WriteLine("Visiting " + start.NodeValue.ToString());
                 start.Visited = true;
                 for (int i = 0; i < start.NeighborNodes.Count; i++)
                     if (!start.NeighborNodes[i].Visited)
                     {
                         if (DFS_Recursive(start.NeighborNodes[i], goal))
                             return true;
                     }
  
             }
             else
             {
                 Console.WriteLine("Recursive DFS found goal node.\n");
                 return true;
                 
             }
 
             return false;
         }
 
         public void BFS(Node start, Node goal)
         {
             Queue<Node> queue = new Queue<Node>();
             queue.Enqueue(start);
             while (queue.Count > 0)
             {
                 Node node = queue.Dequeue();
                 if (node.Visited)
                     continue;
                 else
                 {
                     Console.WriteLine("visiting " + node.NodeValue.ToString());
                     if (node == goal)
                     {
                         Console.WriteLine("BFS found goal node.");
                         return;
                     }
                     node.Visited = true;
                     for (int i = 0; i < node.NeighborNodes.Count; i++)
                     {
                         if (!node.NeighborNodes[i].Visited)
                             queue.Enqueue(node.NeighborNodes[i]);
                     }
                 }
             }
 
             Console.WriteLine("BFS did not find goal node.");
         }
 
         public override void BuildAdjacencyList()
         {
 
             // Create the nodes.
             for (int i = 0; i <= 15; i++)
                 // Add a node with NodeVal = i.
                 _nLst.Add(new Node(i));
             
             _root = _nLst[0];
             _goal = _nLst[15];
 
             // Add connections.
             _root.AddNodes(new Node[]{_nLst[1], _nLst[5], _nLst[9]});
             
             _nLst[1].AddNodes(new Node[] { _nLst[2], _nLst[3], _root });
             _nLst[2].AddNodes(new Node[] { _nLst[1] });
             _nLst[3].AddNodes(new Node[] { _nLst[4], _nLst[1] });
             _nLst[4].AddNodes(new Node[] { _nLst[3] });
             _nLst[5].AddNodes(new Node[] { _nLst[6], _root });
             _nLst[6].AddNodes(new Node[] { _nLst[7], _nLst[5] });
             _nLst[7].AddNodes(new Node[] { _nLst[8], _nLst[6] });
             _nLst[8].AddNodes(new Node[] { _nLst[7] });
             _nLst[9].AddNodes(new Node[] { _root, _nLst[10], _nLst[11] });
             _nLst[10].AddNodes(new Node[] { _goal });
             _goal.AddNodes(new Node[] { _nLst[10] });
             _nLst[11].AddNodes(new Node[] { _nLst[9], _nLst[12] });
             _nLst[12].AddNodes(new Node[] { _nLst[11], _nLst[13], _nLst[14] });
             _nLst[13].AddNodes(new Node[] { _nLst[12] });
             _nLst[14].AddNodes(new Node[] { _nLst[12] });
             
         }
 
 

A demonstration program which combines the three previous listings with the node tree shown on the previous page can be run as shown by substituting listings in Listing 1-4, below.  The accompanying figure shows the resulting console output.  
Listing 1-4 Implementation of Simple Tree Search    (Show Code ...)
Listing 1-4 Simple Tree-Search Implementation with Depth First and Breadth First Searches  using System;
 using System.Collections.Generic;
 using System.Text;
 
 namespace TreeSearch
 {
     public class Node
     {
          // Code in Listing 1-1 goes here.
     }
 
     abstract public class AbsTreeSearch
     {
         // Code in Listing 1-2 goes here.
     }
     
     public class SimpleTreeSearch : AbsTreeSearch
     {
         // Code in Listing 1-3 goes here.
     }
     
     static void Main (string[] args)
     {
             SimpleTreeSearch ts = new SimpleTreeSearch(16);
             ts.ShowNodes();
             Console.WriteLine("\n\n\n");
             ts.DFS(ts._root, ts._goal);
             ts.ResetVisitedStates();
             
             if (!ts.DFS_Recursive(ts._root, ts._goal) )
                Console.WriteLine("DFS_Recursive did not find goal node.\n\n");
             
             ts.ResetVisitedStates();
             ts.BFS(ts._root, ts._goal);
             
             Console.ReadLine(); // stop here until user presses any key
     }
 } // end namespace TreeSearch
         
Results of Simple Searches 
Figure 1-2 Results of Simple Tree Searches
1.2 Uninformed Searches with Additional Features

Note that the tree data structure (view here) has no cycles.  But in a connected tree with undirected edges, the goal node will always be found with either the DFS or the BFS because all nodes that can be reached from another node are visited once, and only once, even for nodes that appear in a cycle.  To see a demonstration of this, create a cycle by connecting nodes 3 and 6.  This can be accomplished in BuildAdjacencyList ( ) by changing _nList[3] and _nList[6] as shown below:

             _nList[3].AddNodes (new Node[] {_nLst[4], _nLst[1] });

         becomes

                               _nList[3].AddNodes(new Node[] {_nLst[4], _nLst[1], _nLst[6] });

The node list can have any geometry. It could be a random geometry. Rewrite BuildAdjacencyList ( ) as shown in Listing 1-5 below. (Comment out the old version, if desired.) Create a list with 100 nodes (the value of N on the first line) where each node has three neighbors chosen randomly and the next node in _nList connects to the third neighbor of the previous node guaranteeing that all nodes can be reached starting from anywhere in the graph. By the way, we'll present a Windows application shortly that shows the graph pictorially.
Listing 1-5 An Adjacency List with Randomly Generated Connections    (Show Code ...)
Listing 1-5 Simple Search With Additional Features          public override void BuildAdjacencyList()
         {
             int N = 100;
 
             // Create the nodes.
             for (int i = 0; i < N; i++)
                 _nLst.Add(new Node(i));
 
             _root = _nLst[0];
             _goal = _nLst[N/2];
 
             int seed = (int)System.DateTime.Now.Ticks % System.Int32.MaxValue;
             Random rchild = new Random(seed);
             int randNo1, randNo2, randNo3;
             Node prevNode = _nLst[0];
             for (int i=0; i < N; i++)
             {
                 while ( (randNo1 = rchild.Next(0, N)) == i);
                 while ((randNo2 = rchild.Next(0, N)) == i) ;
                 while ((randNo3 = rchild.Next(0, N)) == i) ;
 
                 _nLst[i].AddNodes(new Node[] {_nLst[randNo1], _nLst[randNo2], 
                     _nLst[randNo3], prevNode });
                 prevNode = _nLst[randNo1];
              }
         }
         


      There's more to come.  Check back often!  Comments?   Send feedback.

< Prev PageHome