Simple Traversals in Binary Trees
A common data structure used in algorithms is a tree (which
actually should have been named “pyramid” since a tree has its root at the
bottom, not at the top) and traversing a tree becomes one of the fundamentals techniques
in computer science. For a simple binary tree, there are basically three
well-known techniques for traversing the tree:
·
Pre-Order: in which you perform some computation
against the current node, then recursively perform the computation for the left
and then the right nodes
·
In-Order: in which you perform some computation
against the left node (recursively), then against the current node then
recursively against the right node (recursively)
·
Post-Order: in which you perform some
computation against the left node (recursively), then against the right node
(recursively) and then against the current node
The following problem can be solved with any of the
traversals above: given a binary tree, determine whether the tree is a Binary
Search Tree (BST). A BST is defined (at least that’s the definition we’re
adopting here) as a binary tree where the value of any node is greater than or
equal to any value in its left sub-tree, and less than or equal to any value of
its right sub-tree.
A pre-order traversal can be done, but requires a double
traversal of the tree (notice that you need to check the entire sub-tree, not
only the current children), hence the cost for the pre-order solution is O(N^2)
where N is the number of nodes. The post-order seems simpler to understand but
requires that we keep track of the max & min values for each sub-tree. It
is however efficient: O(N). The in-order also achieves a O(N) time complexity,
but it does not come to me as intuitive as the post-order solution. Basically
the in-order leverages the fact that if you read the values of the BST from
left to right you’ll have a total order of the elements. In addition, to print
the tree there is another traversal which is a per-level traversal making use
of a queue (instead of a stack, so no recursion there), doing a Breadth-First
Search (BFS) instead of the {Pre, In, Post}-Order traversals, which are all
Depth-First Search (DFS). Code is below:
Tree.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace IsBST
{
class Tree
{
class Node
{
public int
value;
public
Node left;
public
Node right;
public
Node(int value)
{
this.value = value;
this.left = null;
this.right = null;
}
}
class
QueueElement
{
public Node currentNode;
public Node parentNode;
public int level;
public string
relativePositionToParent; //L or R
public
QueueElement(Node currentNode,
Node
parentNode,
int level,
string
relativePositionToParent)
{
this.currentNode = currentNode;
this.parentNode = parentNode;
this.level = level;
this.relativePositionToParent = relativePositionToParent;
}
}
private Node
root;
public Tree()
{
this.root
= null;
}
public void
Print()
{
if
(this.root == null)
{
Console.WriteLine("Tree is empty!");
return;
}
Queue<QueueElement> queue = new Queue<QueueElement>();
int
currentLevel = 0;
QueueElement qe = new QueueElement(this.root, null, 0, "");
queue.Enqueue(qe);
while
(queue.Count > 0)
{
qe =
queue.Dequeue();
if
(qe.level != currentLevel)
{
Console.WriteLine();
currentLevel = qe.level;
}
Console.Write("{0}{1}({2}) ", qe.currentNode.value,
qe.relativePositionToParent,
(qe.parentNode==null)?"root":qe.parentNode.value.ToString());
if
(qe.currentNode.left != null)
{
queue.Enqueue(new QueueElement(qe.currentNode.left, qe.currentNode,
qe.level+1, "L"));
}
if
(qe.currentNode.right != null)
{
queue.Enqueue(new QueueElement(qe.currentNode.right, qe.currentNode,
qe.level+1, "R"));
}
}
Console.WriteLine();
}
public void
AddValueBST(int value)
{
if
(this.root == null)
{
this.root = new Node(value);
}
else
{
Node
currentNode = this.root;
while
(currentNode != null)
{
if
(value < currentNode.value)
{
if (currentNode.left == null)
{
currentNode.left = new Node(value);
return;
}
else
{
currentNode = currentNode.left;
}
}
else
{
if (currentNode.right == null)
{
currentNode.right = new Node(value);
return;
}
else
{
currentNode = currentNode.right;
}
}
}
}
}
public void
AddValueRandomly(int value)
{
if
(this.root == null)
{
this.root = new Node(value);
}
else
{
Node
currentNode = this.root;
while
(currentNode != null)
{
string guid = Guid.NewGuid().ToString();
int seed = 0;
foreach (char c in guid)
{
int number = 0;
if (Int32.TryParse(c.ToString(), out number))
{
seed = (int)((10L * seed + number) % Int32.MaxValue);
}
}
int coinToss = seed % 2;
switch (coinToss)
{
case 0:
if (currentNode.left == null)
{
currentNode.left =
new Node(value);
return;
}
else
{
currentNode =
currentNode.left;
}
break;
case 1:
if (currentNode.right == null)
{
currentNode.right = new Node(value);
return;
}
else
{
currentNode =
currentNode.right;
}
break;
}
}
}
}
public bool
IsBST_PreOrder()
{
return
_IsBST_PreOrder(this.root);
}
public bool
IsBST_PostOrder()
{
int max =
0;
int min =
0;
return
_IsBST_PostOrder(this.root, ref max, ref min);
}
public bool
IsBST_InOrder()
{
int
previousValue = Int32.MinValue;
return
_IsBST_InOrder(this.root, ref previousValue);
}
private bool
_IsBST_InOrder(Node node,
ref int
previousValue)
{
if (node
== null)
{
return
true;
}
//Process
left
if
(!_IsBST_InOrder(node.left, ref previousValue))
{
return
false;
}
//Process
current
if
(node.value < previousValue)
{
return
false;
}
previousValue = node.value;
//Process
right
return
_IsBST_InOrder(node.right, ref previousValue);
}
private bool
_IsBST_PostOrder(Node node,
ref int
max,
ref int
min)
{
if (node
== null)
{
max =
Int32.MinValue;
min =
Int32.MaxValue;
return
true;
}
//Process
left
int lMax =
Int32.MinValue;
int lMin =
Int32.MaxValue;
if
(!_IsBST_PostOrder(node.left,
ref lMax,
ref lMin))
{
return
false;
}
//Process
right
int rMax =
Int32.MinValue;
int rMin =
Int32.MaxValue;
if
(!_IsBST_PostOrder(node.right,
ref rMax,
ref rMin))
{
return
false;
}
//Process
current
if
(node.value < lMax ||
node.value > rMin)
{
return
false;
}
max =
Math.Max(Math.Max(lMax, rMax), node.value);
min =
Math.Min(Math.Min(lMin, rMin), node.value);
return
true;
}
private bool
_IsBST_PreOrder(Node node)
{
if (node
== null)
{
return
true;
}
//Process
current
if
(!_CompareAllElements(node.left, node.value, "greater than or equal")
||
!_CompareAllElements(node.right, node.value, "less than or
equal"))
{
return
false;
}
//Process
left
//Process
right
return
_IsBST_PreOrder(node.left) && _IsBST_PreOrder(node.right);
}
private bool
_CompareAllElements(Node node,
int
value,
string
comparison)
{
if (node
== null)
{
return
true;
}
//Process
current
switch
(comparison)
{
case
"greater than":
if
(value <= node.value)
{
return false;
}
break;
case
"greater than or equal":
if
(value < node.value)
{
return false;
}
break;
case
"less than":
if (value >= node.value)
{
return false;
}
break;
case
"less than or equal":
if
(value > node.value)
{
return false;
}
break;
}
//Process
left
//Process
right
return
_CompareAllElements(node.left, value, comparison) && _CompareAllElements(node.right,
value, comparison);
}
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace IsBST
{
class Program
{
static void
Main(string[] args)
{
int nNodes
= 0;
if
(args.Length == 0 ||
!Int32.TryParse(args[0], out nNodes))
{
Console.WriteLine("Usage: IsBST.exe <number of nodes in the
trees>");
return;
}
Tree
treeBST = new Tree();
Tree
treeRandom = new Tree();
Random rd
= new Random();
for (int i
= 0; i < nNodes; i++)
{
treeBST.AddValueBST(rd.Next(0, 100));
treeRandom.AddValueRandomly(rd.Next(0,
20));
}
Console.WriteLine("BST Tree:");
treeBST.Print();
Console.WriteLine();
Console.WriteLine("Random Tree:");
treeRandom.Print();
Console.WriteLine();
Console.WriteLine("Is the BST Tree a BST (Pre-Order): {0}",
treeBST.IsBST_PreOrder());
Console.WriteLine("Is the BST Tree a BST (Post-Order): {0}",
treeBST.IsBST_PostOrder());
Console.WriteLine("Is the BST Tree a BST (In-Order): {0}",
treeBST.IsBST_InOrder());
Console.WriteLine("Is the Random Tree a BST (Pre-Order): {0}",
treeRandom.IsBST_PreOrder());
Console.WriteLine("Is the Random Tree a BST (Post-Order):
{0}", treeRandom.IsBST_PostOrder());
Console.WriteLine("Is the Random Tree a BST (In-Order): {0}",
treeRandom.IsBST_InOrder());
}
}
}
Hi Marcelo
ReplyDeleteYou should add this code to http://github.com. (This is a public source control where code can be shared) They have nice integration with vs2013 as well as a source control.
Also, you should try Glee library (http://research.microsoft.com/en-us/downloads/f1303e46-965f-401a-87c3-34e1331d32c5/default.aspx) from MSR. It allows drawing tree/graph in UI with circles and lines
Ah, very nice. I've always had problems printing out a b-tree in a nice format. Will take a look, thanks Balaji!
Delete