Comp202: Principles of Object-Oriented Programming II
Fall 2007 -- Lecture #14: Traversing Binary Trees (part 3)   


Breadth-First Traversal

Consider the following binary tree.

               1
            /     \
         2         3
      /    \          \
    4      5           6
                       /
                    7

The breadth first traversal from left to right consists of visiting the nodes: 1, 2, 3, 4, 5, 6, 7 in this order.  To traverse the tree in this manner, each time we visit a non-empty node, we need to save its two children in a FIFO queue, process the current node, then go through the queue and process each node in the queue in the same manner.  Here is the code for printing a tree in breadth-first order.

package brs.visitor;
import brs.*;
import rac.*;
/**
 * Prints the tree nodes in breadth traversal.
 * Uses a FIFO queue.
 * @author DXN
 */
public class BreadthPrint implements IVisitor {
    private IRAContainer _queue = new LRSQueueFactory().makeRAC();    
    // IRAContainer visitor to go through the queue and process each tree
    // in the queus with a given BiTree visitor.
    private IRACVisitor _processQ = new IRACVisitor() {
        public Object emptyCase(IRAContainer q, Object treeVis) {
            return null;
        }

        public Object nonEmptyCase(IRAContainer q, Object treeVis) {
            ((BiTree)q.get()).execute((IVisitor)treeVis, null);
            return q.execute(this, treeVis);
        }
    };
    /**
     * Nothing to print here.
     */
    public Object emptyCase(BiTree host, Object nu) {
        return null;
    }
    /**
     * Prints the root data, saves the left and right subtrees in _queue
     * and "process" _queue.
     */
    public Object nonEmptyCase(BiTree host, Object nu) {
        _queue.put(host.getLeftSubTree());
        _queue.put(host.getRightSubTree());
        System.out.print(host.getRootDat());
        return _queue.execute(_processQ, new IVisitor() {
            public Object emptyCase(BiTree h, Object nu) {
                return null;
            }

            public Object nonEmptyCase(final BiTree h, Object nu) {
                _queue.put(h.getLeftSubTree());
                _queue.put(h.getRightSubTree());
                System.out.print(" " + h.getRootDat());
                return null;
            }
        });
    }

    /**
     * Simple test code.
     */
    public static void main(String[] args) {
        BiTree t0 = new BiTree();
        t0.insertRoot(new Integer(1));
        BiTree t1 = new BiTree();
        t1.insertRoot(new Integer(2));
        BiTree t2 = new BiTree();
        t2.insertRoot(new Integer(3));
        t0.setLeftSubTree(t1);
        t0.setRightSubTree(t2);
        t1.getLeftSubTree().insertRoot(new Integer(4));
        t1.getLeftSubTree().getRightSubTree().insertRoot(new Integer(6));
        t2.getRightSubTree().insertRoot(new Integer(5));
        t2.getRightSubTree().getLeftSubTree().insertRoot(new Integer(7));
        System.out.println("t0 is: \n" + t0 + "\n");
        System.out.println("Breadth first traversal:");
        t0.execute(new BreadthPrint(), null);
        System.out.println("\nDone!");
    }
}

What is the abstract processing here?  Use a lambda where you see System.out.println.  Here is the code for the invariant breadth-first tree traversal, where the variant is simply a lambda.

package brs.visitor;
import brs.*;
import rac.*;
import fp.*;
/**
 * Processes the tree nodes via breadth-first traversal.
 * Uses a FIFO queue.
 * @author DXN
 */
public class BreadthFirst implements IVisitor {
    private IRAContainer _queue = new LRSQueueFactory().makeRAC();
    private ILambda _f;
    private Object _acc; // accumulated result.
    // IRAContainer visitor to go through the queue and process each tree
    // in the queus with a given BiTree visitor.
    private IRACVisitor _processQ = new IRACVisitor() {
        public Object emptyCase(IRAContainer q, Object treeVis) {
            return _acc;
        }

        public Object nonEmptyCase(IRAContainer q, Object treeVis) {
            ((BiTree)q.get()).execute((IVisitor)treeVis, null);
            return q.execute(this, treeVis);
        }
    };

    
    public BreadthFirst(ILambda f) {
        _f = f;
    }
    /**
     */
    public Object emptyCase(BiTree host, Object b) {
        return b;
    }
    /**
     * Processes the root data, saves the left and right subtrees in _queue
     * and "process" _queue.
     */
    public Object nonEmptyCase(BiTree host, final Object b) {
        _queue.put(host.getLeftSubTree());
        _queue.put(host.getRightSubTree());
        _acc = _f.apply(host, b);
        return _queue.execute(_processQ, new IVisitor() {
            public Object emptyCase(BiTree h, Object nu) {
                return b;  // anything, _acc ok too.
            }

            public Object nonEmptyCase(final BiTree h, Object nu) {
                _queue.put(h.getLeftSubTree());
                _queue.put(h.getRightSubTree());
                _acc = _f.apply(h, _acc);
                return _acc;
            }
        });
    }

            
    /**
    * Simple test code.
     */
    public static void main(String[] args) {
        BiTree t0 = new BiTree();
        t0.insertRoot(new Integer(1));
        BiTree t1 = new BiTree();
        t1.insertRoot(new Integer(2));
        BiTree t2 = new BiTree();
        t2.insertRoot(new Integer(3));
        t0.setLeftSubTree(t1);
        t0.setRightSubTree(t2);
        t1.getLeftSubTree().insertRoot(new Integer(4));
        t1.getLeftSubTree().getRightSubTree().insertRoot(new Integer(6));
        t2.getRightSubTree().insertRoot(new Integer(5));
        t2.getRightSubTree().getLeftSubTree().insertRoot(new Integer(7));
        System.out.println("t0 is: \n" + t0 + "\n");
        System.out.println("Breadth first printing:");

        ILambda print = new ILambda() {
            public Object apply(Object... args) {
                System.out.print("" + args[1] + ((BiTree)args[0]).getRootDat());
                return " ";
            }
        };

        t0.execute(new BreadthFirst(print), "");
        System.out.println("\nBreadth first adding:");
        ILambda add= new ILambda() {
            public Object apply(Object... args) {
                return (Integer)args[1] + (Integer)((BiTree)args[0]).getRootDat();
            }
        };
        System.out.println(t0.execute(new BreadthFirst(add), 0));
        System.out.println("\nDone!");
    }
}

 

 


Last Revised Thursday, 03-Jun-2010 09:52:33 CDT

©2007 Stephen Wong and Dung Nguyen