Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Display a Binary Search Tree in Console

Tags:

I have simple binary search tree

public class BNode {     public int item;     public BNode right;     public BNode left;      public BNode(int item)     {         this.item = item;     } }  public class BTree {     private BNode _root;     private int _count;     private IComparer<int> _comparer = Comparer<int>.Default;       public BTree()     {         _root = null;         _count = 0;     }       public bool Add(int Item)     {         if (_root == null)         {             _root = new BNode(Item);             _count++;             return true;         }         else         {             return Add_Sub(_root, Item);         }     }      private bool Add_Sub(BNode Node, int Item)     {         if (_comparer.Compare(Node.item, Item) < 0)         {             if (Node.right == null)             {                 Node.right = new BNode(Item);                 _count++;                 return true;             }             else             {                 return Add_Sub(Node.right, Item);             }         }         else if (_comparer.Compare(Node.item, Item) > 0)         {             if (Node.left == null)             {                 Node.left = new BNode(Item);                 _count++;                 return true;             }             else             {                 return Add_Sub(Node.left, Item);             }         }         else         {             return false;         }     }      public void Print()     {         Print(_root, 4);     }      public void Print(BNode p, int padding)     {         if (p != null)         {             if (p.right != null)             {                 Print(p.right, padding + 4);             }             if (padding > 0)             {                 Console.Write(" ".PadLeft(padding));             }             if (p.right != null)             {                 Console.Write("/\n");                 Console.Write(" ".PadLeft(padding));             }             Console.Write(p.item.ToString() + "\n ");             if (p.left != null)             {                 Console.Write(" ".PadLeft(padding) + "\\\n");                 Print(p.left, padding + 4);             }         }     } } 

where I can insert values like

BTree btr = new BTree(); btr.Add(6); btr.Add(2); btr.Add(3); btr.Add(11); btr.Add(30); btr.Add(9); btr.Add(13); btr.Add(18); 

I want to display my tree within my console application. I have a btr.Print(); which displays my tree from left to right (6 is the root) - but I'm not happy with it.

enter image description here

Question: Is there a better way to display this tree within a console application? Even a improvement of this Print() would help me.

like image 582
fubo Avatar asked Mar 30 '16 14:03

fubo


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

What is C in C language?

What is C? C is a general-purpose programming language created by Dennis Ritchie at the Bell Laboratories in 1972. It is a very popular language, despite being old. C is strongly associated with UNIX, as it was developed to write the UNIX operating system.

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.

Is C language easy?

Compared to other languages—like Java, PHP, or C#—C is a relatively simple language to learn for anyone just starting to learn computer programming because of its limited number of keywords.


2 Answers

I've ended up with the following method that allows you to print arbitrary subtree:

public static class BTreePrinter {     class NodeInfo     {         public BNode Node;         public string Text;         public int StartPos;         public int Size { get { return Text.Length; } }         public int EndPos { get { return StartPos + Size; } set { StartPos = value - Size; } }         public NodeInfo Parent, Left, Right;     }      public static void Print(this BNode root, string textFormat = "0", int spacing = 1, int topMargin = 2, int leftMargin = 2)     {         if (root == null) return;         int rootTop = Console.CursorTop + topMargin;         var last = new List<NodeInfo>();         var next = root;         for (int level = 0; next != null; level++)         {             var item = new NodeInfo { Node = next, Text = next.item.ToString(textFormat) };             if (level < last.Count)             {                 item.StartPos = last[level].EndPos + spacing;                 last[level] = item;             }             else             {                 item.StartPos = leftMargin;                 last.Add(item);             }             if (level > 0)             {                 item.Parent = last[level - 1];                 if (next == item.Parent.Node.left)                 {                     item.Parent.Left = item;                     item.EndPos = Math.Max(item.EndPos, item.Parent.StartPos - 1);                 }                 else                 {                     item.Parent.Right = item;                     item.StartPos = Math.Max(item.StartPos, item.Parent.EndPos + 1);                 }             }             next = next.left ?? next.right;             for (; next == null; item = item.Parent)             {                 int top = rootTop + 2 * level;                 Print(item.Text, top, item.StartPos);                 if (item.Left != null)                 {                     Print("/", top + 1, item.Left.EndPos);                     Print("_", top, item.Left.EndPos + 1, item.StartPos);                 }                 if (item.Right != null)                 {                     Print("_", top, item.EndPos, item.Right.StartPos - 1);                     Print("\\", top + 1, item.Right.StartPos - 1);                 }                 if (--level < 0) break;                 if (item == item.Parent.Left)                 {                     item.Parent.StartPos = item.EndPos + 1;                     next = item.Parent.Node.right;                 }                 else                 {                     if (item.Parent.Left == null)                         item.Parent.EndPos = item.StartPos - 1;                     else                         item.Parent.StartPos += (item.StartPos - 1 - item.Parent.EndPos) / 2;                 }             }         }         Console.SetCursorPosition(0, rootTop + 2 * last.Count - 1);     }      private static void Print(string s, int top, int left, int right = -1)     {         Console.SetCursorPosition(left, top);         if (right < 0) right = left + s.Length;         while (Console.CursorLeft < right) Console.Write(s);     } } 

As you can see, I've added some parameters that affect the formatting. By default it produces the most compact representation.

In order to play with it, I've modified the BTree class as follows:

public class BTree {     // ...      public BNode Root { get { return _root; } }      public void Print()     {         Root.Print();     } } 

Using your sample data, here are some results:

btr.Root.Print();

enter image description here

btr.Root.Print(textFormat: "(0)", spacing: 2);

enter image description here

UPDATE: IMO the default format above is compact and readable, but just for fun, adjusted the algorithm to produce more "graphical" output (textFormat and spacing parameters removed):

public static class BTreePrinter {     class NodeInfo     {         public BNode Node;         public string Text;         public int StartPos;         public int Size { get { return Text.Length; } }         public int EndPos { get { return StartPos + Size; } set { StartPos = value - Size; } }         public NodeInfo Parent, Left, Right;     }      public static void Print(this BNode root, int topMargin = 2, int leftMargin = 2)     {         if (root == null) return;         int rootTop = Console.CursorTop + topMargin;         var last = new List<NodeInfo>();         var next = root;         for (int level = 0; next != null; level++)         {             var item = new NodeInfo { Node = next, Text = next.item.ToString(" 0 ") };             if (level < last.Count)             {                 item.StartPos = last[level].EndPos + 1;                 last[level] = item;             }             else             {                 item.StartPos = leftMargin;                 last.Add(item);             }             if (level > 0)             {                 item.Parent = last[level - 1];                 if (next == item.Parent.Node.left)                 {                     item.Parent.Left = item;                     item.EndPos = Math.Max(item.EndPos, item.Parent.StartPos);                 }                 else                 {                     item.Parent.Right = item;                     item.StartPos = Math.Max(item.StartPos, item.Parent.EndPos);                 }             }             next = next.left ?? next.right;             for (; next == null; item = item.Parent)             {                 Print(item, rootTop + 2 * level);                 if (--level < 0) break;                 if (item == item.Parent.Left)                 {                     item.Parent.StartPos = item.EndPos;                     next = item.Parent.Node.right;                 }                 else                 {                     if (item.Parent.Left == null)                         item.Parent.EndPos = item.StartPos;                     else                         item.Parent.StartPos += (item.StartPos - item.Parent.EndPos) / 2;                 }             }         }         Console.SetCursorPosition(0, rootTop + 2 * last.Count - 1);     }      private static void Print(NodeInfo item, int top)     {         SwapColors();         Print(item.Text, top, item.StartPos);         SwapColors();         if (item.Left != null)             PrintLink(top + 1, "┌", "┘", item.Left.StartPos + item.Left.Size / 2, item.StartPos);         if (item.Right != null)             PrintLink(top + 1, "└", "┐", item.EndPos - 1, item.Right.StartPos + item.Right.Size / 2);     }      private static void PrintLink(int top, string start, string end, int startPos, int endPos)     {         Print(start, top, startPos);         Print("─", top, startPos + 1, endPos);         Print(end, top, endPos);     }      private static void Print(string s, int top, int left, int right = -1)     {         Console.SetCursorPosition(left, top);         if (right < 0) right = left + s.Length;         while (Console.CursorLeft < right) Console.Write(s);     }      private static void SwapColors()     {         var color = Console.ForegroundColor;         Console.ForegroundColor = Console.BackgroundColor;         Console.BackgroundColor = color;     } } 

and the result is:

enter image description here

like image 95
Ivan Stoev Avatar answered Oct 29 '22 19:10

Ivan Stoev


This is my take at it:

I've added PrintPretty to BNode, and I've removed the second Print function you had in BTree.

(Edit: I made the tree more lisible by changing the original chars to draw the branches of the tree)

    static void Main(string[] args)     {         BTree btr = new BTree();         btr.Add(6);         btr.Add(2);         btr.Add(3);         btr.Add(11);         btr.Add(30);         btr.Add(9);         btr.Add(13);         btr.Add(18);          btr.Print();      }      public class BNode     {         public int item;         public BNode right;         public BNode left;          public BNode(int item)         {             this.item = item;         }          public void PrintPretty(string indent, bool last)         {              Console.Write(indent);             if (last)             {                 Console.Write("└─");                 indent += "  ";             }             else             {                 Console.Write("├─");                 indent += "| ";             }             Console.WriteLine(item);              var children = new List<BNode>();             if (this.left != null)                 children.Add(this.left);             if (this.right != null)                 children.Add(this.right);              for (int i = 0; i < children.Count; i++)                 children[i].PrintPretty(indent, i == children.Count - 1);          }      }      public class BTree     {         private BNode _root;         private int _count;         private IComparer<int> _comparer = Comparer<int>.Default;           public BTree()         {             _root = null;             _count = 0;         }           public bool Add(int Item)         {             if (_root == null)             {                 _root = new BNode(Item);                 _count++;                 return true;             }             else             {                 return Add_Sub(_root, Item);             }         }          private bool Add_Sub(BNode Node, int Item)         {             if (_comparer.Compare(Node.item, Item) < 0)             {                 if (Node.right == null)                 {                     Node.right = new BNode(Item);                     _count++;                     return true;                 }                 else                 {                     return Add_Sub(Node.right, Item);                 }             }             else if (_comparer.Compare(Node.item, Item) > 0)             {                 if (Node.left == null)                 {                     Node.left = new BNode(Item);                     _count++;                     return true;                 }                 else                 {                     return Add_Sub(Node.left, Item);                 }             }             else             {                 return false;             }         }          public void Print()         {             _root.PrintPretty("", true);         }      } 

This is the result (more compact, as I mentioned):

enter image description here


Edit: the following code has been modified in order to show the info about left-right:

    static void Main(string[] args)     {         BTree btr = new BTree();         btr.Add(6);         btr.Add(2);         btr.Add(3);         btr.Add(11);         btr.Add(30);         btr.Add(9);         btr.Add(13);         btr.Add(18);          btr.Print();      }      public enum NodePosition     {         left,         right,         center     }      public class BNode     {         public int item;         public BNode right;         public BNode left;          public BNode(int item)         {             this.item = item;         }          private void PrintValue(string value, NodePosition nodePostion)         {             switch (nodePostion)             {                 case NodePosition.left:                     PrintLeftValue(value);                     break;                 case NodePosition.right:                     PrintRightValue(value);                     break;                 case NodePosition.center:                     Console.WriteLine(value);                     break;                 default:                     throw new NotImplementedException();             }         }          private void PrintLeftValue(string value)         {             Console.ForegroundColor = ConsoleColor.Magenta;             Console.Write("L:");             Console.ForegroundColor = (value == "-") ? ConsoleColor.Red : ConsoleColor.Gray;             Console.WriteLine(value);             Console.ForegroundColor = ConsoleColor.Gray;         }          private void PrintRightValue(string value)         {             Console.ForegroundColor = ConsoleColor.Green;             Console.Write("R:");             Console.ForegroundColor = (value == "-") ? ConsoleColor.Red : ConsoleColor.Gray;             Console.WriteLine(value);             Console.ForegroundColor = ConsoleColor.Gray;         }          public void PrintPretty(string indent, NodePosition nodePosition, bool last, bool empty)         {              Console.Write(indent);             if (last)             {                 Console.Write("└─");                 indent += "  ";             }             else             {                 Console.Write("├─");                 indent += "| ";             }              var stringValue = empty ? "-" : item.ToString();             PrintValue(stringValue, nodePosition);              if(!empty && (this.left != null || this.right != null))             {                 if (this.left != null)                     this.left.PrintPretty(indent, NodePosition.left, false, false);                 else                     PrintPretty(indent, NodePosition.left, false, true);                  if (this.right != null)                     this.right.PrintPretty(indent, NodePosition.right, true, false);                 else                     PrintPretty(indent, NodePosition.right, true, true);             }         }      }      public class BTree     {         private BNode _root;         private int _count;         private IComparer<int> _comparer = Comparer<int>.Default;           public BTree()         {             _root = null;             _count = 0;         }           public bool Add(int Item)         {             if (_root == null)             {                 _root = new BNode(Item);                 _count++;                 return true;             }             else             {                 return Add_Sub(_root, Item);             }         }          private bool Add_Sub(BNode Node, int Item)         {             if (_comparer.Compare(Node.item, Item) < 0)             {                 if (Node.right == null)                 {                     Node.right = new BNode(Item);                     _count++;                     return true;                 }                 else                 {                     return Add_Sub(Node.right, Item);                 }             }             else if (_comparer.Compare(Node.item, Item) > 0)             {                 if (Node.left == null)                 {                     Node.left = new BNode(Item);                     _count++;                     return true;                 }                 else                 {                     return Add_Sub(Node.left, Item);                 }             }             else             {                 return false;             }         }          public void Print()         {             _root.PrintPretty("", NodePosition.center, true, false);         }      } 

The result:

enter image description here

like image 43
Xavier Peña Avatar answered Oct 29 '22 19:10

Xavier Peña