Jay_

C# Binary Trees - Edge Hill University

Nov 5th, 2012
138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 22.10 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. namespace BinaryTree
  7. {
  8. /// <summary>
  9. /// The BinaryTree class implements a simple non-balanced sorted Binary Tree in C#
  10.     /// From http://www.dijksterhuis.org/implementing-a-generic-binary-tree-in-c/
  11. /// </summary>
  12. /// <typeparam name="T">The tree can contain any type, but you are required to provide your own comparison function.</typeparam>
  13.  
  14.     class BinaryTree<T>
  15.     {
  16.         /// <summary>
  17.         /// The tree is build up out of BinaryTreeNode instances
  18.         /// </summary>
  19.  
  20.         class BinaryTreeNode
  21.         {
  22.             public BinaryTreeNode Left;
  23.             public BinaryTreeNode Right;
  24.             public BinaryTreeNode Parent;
  25.             public T Data;
  26.  
  27.             public BinaryTreeNode()
  28.             {
  29.                 Left = null;
  30.                 Right = null;
  31.                 Parent = null;
  32.             }
  33.         }
  34.  
  35.         BinaryTreeNode Root;
  36.         Comparison<T> CompareFunction;
  37.  
  38.         /// <summary>
  39.         /// The BinaryTree constructor requires that we pass a comparison function. We need one as generics can only
  40.         /// be compared as equals, but not for order. The solution is to allow the caller to pass a suitable comparison
  41.         /// function. We use the C# Comparison delegate for this (found in System.Collections)
  42.         /// </summary>
  43.  
  44.         /// <param name="theCompareFunction">Pass a delegate function of the type Comparison to the function</param>
  45.  
  46.         public BinaryTree(Comparison<T> theCompareFunction)
  47.         {
  48.             Root = null;
  49.             CompareFunction = theCompareFunction;
  50.         }
  51.  
  52.         /// <summary>
  53.         /// For integer comparisons we provide a demonstration function.
  54.         /// </summary>
  55.         /// <param name="left"></param>
  56.         /// <param name="right"></param>
  57.         /// <returns>&lt;0 for left smaller than right, &gt;0 if they are equal, +1 if right is larger than left</returns>
  58.  
  59.         public static int CompareFunction_Int(int left, int right)
  60.         {
  61.             return left - right;
  62.         }
  63.  
  64.         public void preorderTraversal()
  65.         {
  66.             // Left children, then right children
  67.             // eg 5213
  68.             // 5
  69.             // 2
  70.             // 1
  71.             // 3
  72.            
  73.             if (Root != null)
  74.             {
  75.                 // node in the tree we wish to process
  76.                 BinaryTreeNode currentNode = Root;
  77.  
  78.                 BinaryTreeNode lastNode = Root;
  79.                 Boolean process = true;
  80.                 int nodesProcessed = 0;
  81.                 while (nodesProcessed != 11)
  82.                 {
  83.                     if (process)
  84.                     {
  85.                         Console.Write(currentNode.Data.ToString());
  86.                         nodesProcessed = nodesProcessed + 1;
  87.                     }
  88.                     process = true;
  89.  
  90.                     // The node is not left, the last node is not left or right
  91.  
  92.                     if (currentNode.Left != null && lastNode != currentNode.Left && lastNode != currentNode.Right)
  93.                     {
  94.                         // Shift it to the left
  95.                         lastNode = currentNode;
  96.                         currentNode = currentNode.Left;
  97.                     }
  98.  
  99.                     // The current node is not right, so shift it to the right
  100.                     else if (currentNode.Right != null && lastNode != currentNode.Right)
  101.                     {
  102.                         lastNode = currentNode;
  103.                         currentNode = currentNode.Right;
  104.                     }
  105.  
  106.                     // Its on the parent node, set the flag to false so that it does
  107.                       // not increment the loop and repeat the process
  108.                     else if (currentNode.Parent != null)
  109.                     {
  110.                         lastNode = currentNode;
  111.                         currentNode = currentNode.Parent;
  112.                         process = false;
  113.                     }
  114.                 }
  115.             }
  116.             else
  117.             {
  118.                 Console.WriteLine("There is no tree to process");
  119.             }
  120.         }
  121.  
  122.  
  123.  
  124.         // InORDER:
  125.         // IF LEFT EXISTS, GOTO AND PROCESS
  126.         // ELSE PROCESS PARENT NODE
  127.         // IF RIGHT EXSISTS, TRANSFER AND PROCESS
  128.        
  129.  
  130.         public void inorderTraversal()
  131.         {
  132.             // No node exists.
  133.             if (Root == null)
  134.             {
  135.                 Console.WriteLine("There is no tree to process");
  136.                 return;
  137.             }
  138.  
  139.             BinaryTreeNode currentNode = Root;
  140.             BinaryTreeNode lastNode = Root;
  141.             Boolean process = true;
  142.             int nodesProcessed = 0;
  143.  
  144.             while (nodesProcessed != 11)
  145.             {
  146.                 if (process)
  147.                 {
  148.                     Console.Write(currentNode.Data.ToString());
  149.                     nodesProcessed = nodesProcessed + 1;
  150.                 }
  151.                 process = true;
  152.  
  153.  
  154.                 // Are there any left nodes available?
  155.                 if (currentNode.Left != null)
  156.                 {
  157.                     // OK
  158.                     // Step 1: Go to furtherest most left node:
  159.                     while (currentNode.Left != null)
  160.                     {
  161.                         lastNode = currentNode;
  162.                         currentNode = currentNode.Left;
  163.                     }
  164.  
  165.                     // Ok we're at the left most node, process it.
  166.                     process = true; // Don't have to include this, just makes it more readable
  167.                     continue;
  168.                 }
  169.  
  170.                 // No left nodes - process parent node then check the right.
  171.                 else if (currentNode.Parent != null)
  172.                 {
  173.                     lastNode = currentNode;
  174.                     currentNode = currentNode.Parent;
  175.  
  176.                     process = true; // Don't have to include this, just makes it more readable
  177.                     continue;
  178.                 }
  179.                     // Finally check for any right nodes
  180.                 else if (currentNode.Right != null)
  181.                 {
  182.                     lastNode = currentNode;
  183.                     currentNode = currentNode.Right;
  184.                     process = true; // readability
  185.                 }
  186.  
  187.             }
  188.  
  189.         }
  190.  
  191.         /*
  192.          
  193.          NOT WORKING
  194.  
  195.         public void postorderTraversal()
  196.         {
  197.             if (Root != null)
  198.             {
  199.                 BinaryTreeNode currentNode = Root;
  200.                 BinaryTreeNode lastNode = Root;
  201.                
  202.                 //  Skip the root, set the initial process as false
  203.                 Boolean process = false;
  204.  
  205.                 int nodesProcessed = 0;
  206.                 while (nodesProcessed != 11)
  207.                 {
  208.                     // Processed a new node
  209.                     // print it out and increment the number of nodes processed so we can
  210.                     // keep track when 11 is up
  211.                     if (process == true)
  212.                     {
  213.                         Console.Write(currentNode.Data.ToString() + " ");
  214.                         nodesProcessed++;
  215.                     }
  216.  
  217.  
  218.  
  219.                     // The node is not left, the last node is not left or right
  220.  
  221.                     if (currentNode.Left != null && lastNode != currentNode.Left && lastNode != currentNode.Right)
  222.                     {
  223.                         // Shift it to the left
  224.                         lastNode = currentNode;
  225.                         currentNode = currentNode.Left;
  226.                     }
  227.  
  228.                     // The current node is not right, so shift it to the right
  229.                     else if (currentNode.Right != null && lastNode != currentNode.Right)
  230.                     {
  231.                         lastNode = currentNode;
  232.                         currentNode = currentNode.Right;
  233.                     }
  234.  
  235.                     // Its on the parent node, set the flag to false so that it does
  236.                     // not increment the loop and repeat the process
  237.                     else if (currentNode.Parent != null)
  238.                     {
  239.                         lastNode = currentNode;
  240.                         currentNode = currentNode.Parent;
  241.                         process = false;
  242.                     }
  243.  
  244.  
  245.  
  246.  
  247.         */
  248.  
  249.  
  250.  
  251.  
  252.  
  253.  
  254.               /*      // Are there any left children?
  255.                     if (currentNode.Left != null)
  256.                     {
  257.                         if (left_side == false)
  258.                         {
  259.                             left_side = true;
  260.                         }
  261.  
  262.                         lastNode = currentNode;
  263.                         currentNode = currentNode.Left;
  264.                         process = false;
  265.                     }
  266.                     // Okay if its looping through the left side and there aren't any children
  267.                     // left we've reached the final one so we can go back up to the parent then proceed to the right
  268.      
  269.                     else if (left_side == true && currentNode.Left == null)
  270.                     {
  271.                         left_side = false;
  272.                         process = true;
  273.                         lastNode = currentNode;
  274.                         currentNode = currentNode.Parent;
  275.                         continue;
  276.                     }
  277.  
  278.                     if (currentNode == currentNode.Parent)
  279.                     {
  280.                         if(
  281.                     }
  282.                    
  283.                     */
  284.                    
  285.                    
  286.                    
  287.                    
  288.                    
  289.                    
  290.                    
  291.                    
  292.                    
  293.                    
  294.                     /*//         process = true;
  295.  
  296.        
  297.                     // There are NO more nodes on the left
  298.                     if (currentNode.Left == null)
  299.                     {
  300.                //         Console.WriteLine("  its null");
  301.            
  302.                         // Now shift to the right
  303.                         if (currentNode.Right != null)
  304.                         {
  305.                             lastNode = currentNode;
  306.                             currentNode = currentNode.Right;
  307.                             currentNode.Left = null;
  308.                         }
  309.                     }
  310.  
  311.                     // This is NOT the last child on the left
  312.                     // so do not process it
  313.                     if (currentNode.Left != null)
  314.                     {
  315.                         lastNode = currentNode;
  316.                         currentNode = currentNode.Left;
  317.                         process = false;
  318.                     }
  319.                     else
  320.                     {
  321.                         process = true;
  322.                     }
  323.    
  324.  
  325.  
  326.  
  327.  
  328.                     */
  329.  
  330.  
  331.  
  332.  
  333.                     // First step: needs to go through all the left children
  334.                    
  335.                     /*
  336.                     // PRINT ALL LEFT CHILDREN, ONLY ONCE
  337.                     if (currentNode.Left != null)
  338.                     {
  339.                         if (currentNode.Left == lastNode)
  340.                         {
  341.                             // root is the default objects that these are assigned to
  342.                             // so add an exception for this
  343.                             if (currentNode != Root && lastNode != Root)
  344.                             {
  345.                                 process = false;
  346.                             }
  347.                             continue;
  348.                         }
  349.  
  350.                         lastNode = currentNode;
  351.                         currentNode = currentNode.Left;
  352.                     }
  353.  
  354.                     */
  355.                     /*
  356.                     // There is (another) left child that exists.
  357.                    
  358.                     if (currentNode.Left != null)
  359.                     {
  360.                         // This is another node in the list
  361.                         if (currentNode != lastNode)
  362.                         {
  363.                             lastNode = currentNode;
  364.                             currentNode = currentNode.Left;
  365.                             continue;
  366.                         }
  367.                         else if (currentNode == lastNode && currentNode != Root)
  368.                         {
  369.                             process = false;
  370.                         }
  371.              //           else if (currentNode == lastNode)
  372.                //         {
  373.                  //           process = false;
  374.                    //     }
  375.                      * }
  376.                     */
  377.  
  378.                    
  379. /*
  380.                     // No more children on the left side.
  381.                     // Go back up to the root
  382.                     else if(currentNode.Left == null)
  383.                     {
  384.                         lastNode = currentNode;
  385.                         currentNode = currentNode.Parent;
  386.          
  387.                         // Skip the process here or it will just go back through
  388.                         process = false;
  389.                     }
  390.                    
  391.                     // there is a right node here
  392.                     if (currentNode.Right != null)
  393.                     {
  394.                         // process it!
  395.                         lastNode = currentNode;
  396.                         currentNode = currentNode.Right;
  397.                     }*
  398.  
  399.                 }
  400.             }
  401.             else
  402.             {
  403.                 Console.WriteLine("There is no tree to process");
  404.             }
  405.         }
  406.         */
  407.        
  408.        
  409.         /// <summary>
  410.         /// For string comparisons we provide a demonstration function
  411.         /// </summary>
  412.         /// <param name="left"></param>
  413.         /// <param name="right"></param>
  414.         /// <returns>-1 for left smaller than right, 0 if they are equal, +1 if right is larger than left</returns>
  415.  
  416.         public static int CompareFunction_String(string left, string right)
  417.         {
  418.             return left.CompareTo(right);
  419.         }
  420.  
  421.         /// <summary>
  422.         /// The add function uses non-recursive tree traversal to find the next available insertion point
  423.         /// </summary>
  424.         /// <param name="Value">The value to insert into tree.</param>
  425.  
  426.         public void Add(T Value)
  427.         {
  428.             BinaryTreeNode child = new BinaryTreeNode();
  429.             child.Data = Value;
  430.             // Is the tree empty? Make the root the new child
  431.             if (Root == null)
  432.             {
  433.                 Root = child;
  434.             }
  435.             else
  436.             {
  437.                 // Start from the root of the tree
  438.                 BinaryTreeNode Iterator = Root;
  439.                 while (true)
  440.                 {
  441.                     // Compare the value to insert with the value in the current tree node
  442.                     int Compare = CompareFunction(Value, Iterator.Data);
  443.                     // The value is smaller or equal to the current node, we need to store it on the left side
  444.  
  445.                     // We test for equivalence as we allow duplicates (!)
  446.                     if (Compare <= 0)
  447.                         if (Iterator.Left != null)
  448.                         {
  449.                             // Travel further left
  450.                             Iterator = Iterator.Left;
  451.                             continue;
  452.                         }
  453.                         else
  454.                         {
  455.                             // An empty left leg, add the new node on the left leg
  456.                             Iterator.Left = child;
  457.                             child.Parent = Iterator;
  458.                             break;
  459.                         }
  460.  
  461.                     if (Compare > 0)
  462.                         if (Iterator.Right != null)
  463.                         {
  464.                             // Continue to travel right
  465.                             Iterator = Iterator.Right;
  466.                             continue;
  467.                         }
  468.                         else
  469.                         {
  470.                             // Add the child to the right leg
  471.                             Iterator.Right = child;
  472.                             child.Parent = Iterator;
  473.                             break;
  474.                         }
  475.                 }
  476.             }
  477.         }
  478.  
  479.         /// <summary>
  480.         /// This routine walks through the tree to see if the value given can be found.
  481.         /// </summary>
  482.         /// <param name="Value">The value to look for in the tree</param>
  483.         /// <returns>True if found, False if not found</returns>
  484.  
  485.         public bool Find(T Value)
  486.         {
  487.             BinaryTreeNode Iterator = Root;
  488.             while (Iterator != null)
  489.             {
  490.                 int Compare = CompareFunction(Value, Iterator.Data);
  491.                 // Did we find the value ?
  492.                 if (Compare == 0) return true;
  493.                 if (Compare < 0)
  494.                 {
  495.                     // Travel left
  496.                     Iterator = Iterator.Left;
  497.                     continue;
  498.                 }
  499.                 // Travel right
  500.                 Iterator = Iterator.Right;
  501.             }
  502.             return false;
  503.         }
  504.  
  505.         /// <summary>
  506.         /// Given a starting node, this routine will locate the left most node in the sub-tree
  507.         /// If no further nodes are found, it returns the starting node
  508.         /// </summary>
  509.  
  510.         /// <param name="start">The sub-tree starting point</param>
  511.         /// <returns></returns>
  512.  
  513.         BinaryTreeNode FindMostLeft(BinaryTreeNode start)
  514.         {
  515.             BinaryTreeNode node = start;
  516.             while (true)
  517.             {
  518.                 if (node.Left != null)
  519.                 {
  520.                     node = node.Left;
  521.                     continue;
  522.                 }
  523.                 break;
  524.             }
  525.             return node;
  526.         }
  527.  
  528.         /// <summary>
  529.         /// Returns a list iterator of the elements in the tree implementing the IENumerator interface.
  530.         /// </summary>
  531.         /// <returns>IENumerator</returns>
  532.  
  533.         public IEnumerator<T> GetEnumerator()
  534.         {
  535.             return new BinaryTreeEnumerator(this);
  536.         }
  537.  
  538.         /// <summary>
  539.         /// The BinaryTreeEnumerator implements the IEnumerator allowing foreach enumeration of the tree
  540.         /// </summary>
  541.  
  542.         class BinaryTreeEnumerator : IEnumerator<T>
  543.         {
  544.             BinaryTreeNode current;
  545.             BinaryTree<T> theTree;
  546.             public BinaryTreeEnumerator(BinaryTree<T> tree)
  547.             {
  548.                 theTree = tree;
  549.                 current = null;
  550.             }
  551.  
  552.             /// <summary>
  553.             /// The MoveNext function traverses the tree in sorted order.
  554.             /// </summary>
  555.  
  556.             /// <returns>True if we found a valid entry, False if we have reached the end</returns>
  557.  
  558.             public bool MoveNext()
  559.             {
  560.                 // For the first entry, find the lowest valued node in the tree
  561.                 if (current == null)
  562.                     current = theTree.FindMostLeft(theTree.Root);
  563.                 else
  564.                 {
  565.                     // Can we go right-left?
  566.                     if (current.Right != null)
  567.                         current = theTree.FindMostLeft(current.Right);
  568.                     else
  569.                     {
  570.                         // Note the value we have found
  571.                         T CurrentValue = current.Data;
  572.                         // Go up the tree until we find a value larger than the largest we have
  573.                         // already found (or if we reach the root of the tree)
  574.                         while (current != null)
  575.                         {
  576.                             current = current.Parent;
  577.                             if (current != null)
  578.                             {
  579.                                 int Compare = theTree.CompareFunction(current.Data,CurrentValue);
  580.                                 if (Compare < 0) continue;
  581.                             }
  582.                             break;
  583.                         }
  584.                     }
  585.                 }
  586.                 return (current != null);
  587.             }
  588.  
  589.             public T Current
  590.             {
  591.                 get
  592.                 {
  593.                     if (current == null)
  594.                         throw new InvalidOperationException();
  595.                     return current.Data;
  596.                 }
  597.             }
  598.  
  599.             object System.Collections.IEnumerator.Current
  600.             {
  601.                 get
  602.                 {
  603.                     if (current == null)
  604.                         throw new InvalidOperationException();
  605.                     return current.Data;
  606.                 }
  607.             }
  608.  
  609.             public void Dispose() { }
  610.  
  611.             public void Reset() { current = null; }
  612.  
  613.         }
  614.     }
  615.  
  616.     class TreeTest
  617.     {
  618.         static BinaryTree<int> Test = new BinaryTree<int>(BinaryTree<int>.CompareFunction_Int);
  619.  
  620.         static void Main(string[] args)
  621.         {
  622.            
  623.             // Build the tree
  624.             Test.Add(5);
  625.             Test.Add(2);
  626.             Test.Add(1);
  627.             Test.Add(3);
  628.             Test.Add(3); // Duplicates are OK
  629.             Test.Add(4);
  630.             Test.Add(6);
  631.             Test.Add(10);
  632.             Test.Add(7);
  633.             Test.Add(8);
  634.             Test.Add(9);
  635.             // Test if we can find values in the tree
  636.  
  637.             for (int Lp = 1; Lp <= 10; Lp++)
  638.                 Console.WriteLine("Find ({0}) = {1}", Lp,Test.Find(Lp));
  639.  
  640.             // Test if we can find a non-existing value
  641.             Console.WriteLine("Find (999) = {0}", Test.Find(999));
  642.  
  643.             // Iterate over all members in the tree -- values are returned in sorted order
  644.             foreach(int value in Test)
  645.             {
  646.                 Console.WriteLine("Value: {0}", value);
  647.             }
  648. //
  649.             Console.WriteLine("Preorder traversal");
  650.             Test.preorderTraversal();
  651. //
  652.             Console.WriteLine("inorder traversal");
  653.             Test.inorderTraversal();
  654.             Console.WriteLine("\n");
  655.         }
  656.  
  657.     }
  658.  
  659. }
Advertisement
Add Comment
Please, Sign In to add comment