Category Archives: Lesson

Stacks to traverse a maze

September 21st, 2015

Using Stacks: Traversing a Maze

Another classic use of a stack data structure is to keep track of alternatives in maze traversal or other similar algorithms that involve trial and error. Suppose that we build a grid as a two-dimensional array of ints where each number represents either a path (1) or a wall (0) in a maze:


  private int [][] grid = { {1,1,1,0,1,1,0,0,0,1,1,1,1},
                        {1,0,0,1,1,0,1,1,1,1,0,0,1},
                        {1,1,1,1,1,0,1,0,1,0,1,0,0},
                        {0,0,0,0,1,1,1,0,1,0,1,1,1},
                        {1,1,1,0,1,1,1,0,1,0,1,1,1},
                        {1,0,1,0,0,0,0,1,1,1,0,0,1},
                        {1,0,1,1,1,1,1,1,0,1,1,1,1},
                        {1,0,0,0,0,0,0,0,0,0,0,0,0},
                        {1,1,1,1,1,1,1,1,1,1,1,1,1} };


Our goal is to start in the top-left corner of this grid and traverse to the bottom- right corner of this grid, traversing only positions that are marked as a path. Valid moves will be those that are within the bounds of the grid and are to cells in the grid marked with a 1. We will mark our path as we go by changing the 1’s to 3’s, and we will push only valid moves onto the stack.
Starting in the top-left corner, we have two valid moves: down and right. We push these moves onto the stack, pop the top move off of the stack (right), and then move to that location. This means that we moved right one position:


                        {3,3,1,0,1,1,0,0,0,1,1,1,1}
                        {1,0,0,1,1,0,1,1,1,1,0,0,1}
                        {1,1,1,1,1,0,1,0,1,0,1,0,0}
                        {0,0,0,0,1,1,1,0,1,0,1,1,1}
                        {1,1,1,0,1,1,1,0,1,0,1,1,1}
                        {1,0,1,0,0,0,0,1,1,1,0,0,1}
                        {1,0,1,1,1,1,1,1,0,1,1,1,1}
                        {1,0,0,0,0,0,0,0,0,0,0,0,0}
                        {1,1,1,1,1,1,1,1,1,1,1,1,1}

We now have only one valid move. We push that move onto the stack, pop the top element off of the stack (right), and then move to that location. Again we moved right one position:

{3,3,3,0,1,1,0,0,0,1,1,1,1}
                        {1,0,0,1,1,0,1,1,1,1,0,0,1}
                        {1,1,1,1,1,0,1,0,1,0,1,0,0}
                        {0,0,0,0,1,1,1,0,1,0,1,1,1}
                        {1,1,1,0,1,1,1,0,1,0,1,1,1}
                        {1,0,1,0,0,0,0,1,1,1,0,0,1}
                        {1,0,1,1,1,1,1,1,0,1,1,1,1}
                        {1,0,0,0,0,0,0,0,0,0,0,0,0}
                        {1,1,1,1,1,1,1,1,1,1,1,1,1}

From this position, we do not have any valid moves. At this point, however, our stack is not empty. Keep in mind that we still have a valid move on the stack left from the first position. We pop the next (and currently last) element off of the stack (down from the first position). We move to that position, push the valid move(s) from that position onto the stack, and continue processing.

 

//********************************************************************
//  Maze.java       Author: Lewis and Chase
//
//  Represents a maze of characters. The goal is to get from the
//  top left corner to the bottom right, following a path of 1s.
//********************************************************************
import jss2.*;
public class Maze
{
   private final int TRIED = 3;
   private final int PATH = 7;

   private int [][] grid = { {1,1,1,0,1,1,0,0,0,1,1,1,1},
                            {1,0,0,1,1,0,1,1,1,1,0,0,1},
                            {1,1,1,1,1,0,1,0,1,0,1,0,0},
                            {0,0,0,0,1,1,1,0,1,0,1,1,1},
                            {1,1,1,0,1,1,1,0,1,0,1,1,1},
                            {1,0,1,0,0,0,0,1,1,1,0,0,1},
                            {1,0,1,1,1,1,1,1,0,1,1,1,1},
                            {1,0,0,0,0,0,0,0,0,0,0,0,0},
                            {1,1,1,1,1,1,1,1,1,1,1,1,1} };

   private StackADT push_new_pos(int x, int y, StackADT stack)
	{
		Position npos = new Position();
		npos.setx(x);
		npos.sety(y);
		if (valid(npos.getx(),npos.gety()))
			stack.push(npos);
		return stack;
	}
		


   //-----------------------------------------------------------------
   //  Attempts to iteratively traverse the maze.  It inserts special
   //  characters indicating locations that have been tried and that
   //  eventually become part of the solution.  This method uses a 
   //  stack to keep track of the possible moves that could be made.
   //-----------------------------------------------------------------
   public boolean traverse ()
   {
      boolean done = false;
      Position pos = new Position();
      Object dispose;
      StackADT stack = new ArrayStack();
      stack.push(pos);

      while (!(done))
	{
		pos = stack.pop();
         	grid[pos.getx()][pos.gety()] = TRIED;  // this cell has been tried
         	if (pos.getx() == grid.length-1 && pos.gety() == grid[0].length-1)
          		done = true;  // the maze is solved
		else
		{
			stack = push_new_pos(pos.getx(),pos.gety() - 1, stack);
			stack = push_new_pos(pos.getx(),pos.gety() + 1, stack); 
			stack = push_new_pos(pos.getx() - 1,pos.gety(), stack); 
			stack = push_new_pos(pos.getx() + 1,pos.gety(), stack); 
		}//else
	}//while

      return done;
   }//method traverse
   
   //-----------------------------------------------------------------
   //  Determines if a specific location is valid.
   //-----------------------------------------------------------------
   private boolean valid (int row, int column)
   {
      boolean result = false;
 
      // Check if cell is in the bounds of the matrix
      if (row >= 0 && row < grid.length &&
          column >= 0 && column < grid[row].length)

         //  Check if cell is not blocked and not previously tried
         if (grid[row][column] == 1)
            result = true;

      return result;
   }//method valid





   //-----------------------------------------------------------------
   //  Returns the maze as a string.
   //-----------------------------------------------------------------
   public String toString ()
   {
      String result = "\n";

      for (int row=0; row < grid.length; row++)
      {
         for (int column=0; column < grid[row].length; column++)
            result += grid[row][column] + "";
         result += "\n";
      }//for

      return result;
   }//method toString
}//class Maze



//********************************************************************
//  MazeSearch.java       Author: Lewis and Chase
//
//  Demonstrates a simulation of recursion using a stack.
//********************************************************************


public class MazeSearch
{
   //-----------------------------------------------------------------
   //  Creates a new maze, prints its original form, attempts to
   //  solve it, and prints out its final form.
   //-----------------------------------------------------------------
   public static void main (String[] args)
   {
      Maze labyrinth = new Maze();
      
      System.out.println (labyrinth);

      if (labyrinth.traverse ())
         System.out.println ("The maze was successfully traversed!");
      else
         System.out.println ("There is no possible path.");

      System.out.println (labyrinth);
   }//method main
}//class MazeSearch

Classwork:
Work in pairs to trace the maze solution by showing the stack contents as it is being traverse. Show the values of the array as you step through elements of the array. Remember to change them as defined above.

Heads up: Tomorrow we will be studying Queues.

 

Symbol Tables Concepts

Definition

A symbol table is a data structure for key-value pairs that supports two operations:

  1. insert (put) a new pair into the table
  2. search for (get) the value associated with a given key

  1. Only one value is associated with each key (no duplicate keys in a table).
  2. When a client puts a key-value pair into a table already containing that key (and
    an associated value), the new value replaces the old one

The associative array abstraction, where you can think of a symbol table as being just like an array, where keys are indices and values are array entries.

In a conventional array, keys are integer indices that we use to quickly access array values; in an associative array (symbol table), keys are of arbitrary type, but we can still use them to quickly access values.

Keys must not be null. As with many mechanisms in Java, use of a null key results in an exception at runtime

In java, no key can be associated with the value null.

Searching cost model
When studying symbol-table implementations, we count compares (equality tests or key comparisons). In (rare) cases where compares are not in the inner loop, we count array accesses.

Priority Queues – Comparable and Comparator

Screen Shot 2016-01-02 at 2.43.31 AM

Implementing Comparable amounts to defining a compareTo() method that implements a natural ordering for the type.

There are many applications where we want to use different orders for the objects that we are sorting, depending on the situation. The Java Comparator interface allows us to build multiple orders within a single class.

Insertion sorting with a Comparator

public static void sort(Object[] a, Comparator c)
  {
     int N = a.length;
     for (int i = 1; i <; N; i++) for (int j = i; j >; 0 && less(c, a[j], a[j-1]); j--)
           exch(a, j, j-1);
}
  private static boolean less(Comparator c, Object v, Object w)
  {  return c.compare(v, w) <; 0;  }
  private static void exch(Object[] a, int i, int j)
  {  Object t = a[i]; a[i] = a[j]; a[j] = t; }


In typical applications, items have multiple instance variables that might need to serve as sort keys.

The sort does each compare through a callback to the compare() method in Transaction that is specified by the client code. To avoid the cost of making a new Comparator object for each sort, we could use public final instance variables to define the comparators (as Java does for CASE_INSENSITIVE_ORDER).

 import java.util.Comparator;
  public class Transaction
  {
     ...
     private final String who;
     private final Date when;
     private final double amount;
     ...
     public static class WhoOrder implements Comparator
     {
        public int compare(Transaction v, Transaction w)
        {  return v.who.compareTo(w.when);  }
     }
     public static class WhenOrder implements Comparator
     {
        public int compare(Transaction v, Transaction w)
        {  return v.when.compareTo(w.when);  }
     }
     public static class HowMuchOrder implements Comparator
     {
        public int compare(Transaction v, Transaction w)
        {
           if (v.amount < w.amount) return -1; if (v.amount > w.amount) return +1;
           return 0;
} }
}

Priority queues with comparators. The same flexibility to use comparators is also useful for priority queues. Extending our standard implementation in Algorithm 2.6 to support comparators involves the following steps:
. Import java.util.Comparator.
. Add to MaxPQ an instance variable comparator and a constructor that takes a 
comparator as argument and initializes comparator to that value.
. Add code to less() that checks whether comparator is null (and uses it if it is 
not null).
For example, with these changes, you could build different priority queues with Transaction keys, using the time, place, or account number for the ordering. If you remove the Key extends Comparable phrase from MinPQ, you even can support keys with no natural order.

ALGORITHM 2.6 Heap priority queue
  public class MaxPQ >
  {
     private Key[] pq;             // heap-ordered complete binary tree
     private int N = 0;            //    in pq[1..N] with pq[0] unused
     public MaxPQ(int maxN)
     {  pq = (Key[]) new Comparable[maxN+1];  }
public boolean isEmpty()
{  return N == 0;  }
public int size()
{  return N;  }
public void insert(Key v)
{
pq[++N] = v;
swim(N); }
public Key delMax()
{
   Key max = pq[1];
   exch(1, N--);
   pq[N+1] = null;
   sink(1);
return max; }
// Retrieve max key from top.
// Exchange with last item.
// Avoid loitering.
// Restore heap property.
     // Missing the implementations of these helper methods.
     private boolean less(int i, int j)
     private void exch(int i, int j)
     private void swim(int k)
     private void sink(int k)
}

MaxPQ

Assignments:
1. Write a telephone lookup program, YI_Telephone.java. Read a data set of 1,000 names and telephone numbers from a file that contains the numbers in random order. Handle lookups by name and also reverse lookups by phone number. Use Comparator and a binary search for both lookups.

2. Write a program, YI_StringLength.java to sort an array list of strings by increasing length. Supply a Comparator.

NOTE:
Callbacks are most easily described in terms of the telephone system. A function call is analogous to calling someone on a telephone, asking her a question, getting an answer, and hanging up; adding a callback changes the analogy so that after asking her a question, you also give her your name and number so she can call you back with the answer.
http://stackoverflow.com/questions/8736378/what-is-a-callback-in-java

BSTs – Proposition

Screen Shot 2015-02-27 at 7.44.59 AM

2-3 search trees
Screen Shot 2015-02-27 at 7.46.26 AM

We introduce in this section a type of binary search tree where costs are guaranteed to be logarithmic. Our trees have near-perfect balance, where the height is guaranteed to be no larger than 2 lg N.

Proposition.

Search and insert operations in a 2-3 tree with N keys are guaranteed to visit at most lg N nodes.

Typical 2-3 tree built from random keys
However, we are only part of the way to an implementation. Although it would be possible to write code that performs transformations on distinct data types representing 2- and 3-nodes, most of the tasks that we have described are inconvenient to implement in this direct representation.

Implementing Binary Search Trees

Binary Trees

Homework:
Implementing Binary Search Trees: With Links

1. How are the constructors implemented?
2. Write the pseudocode for public void addElement (T element). Draw an example of adding an element to a BST.
3. Write the pseudocode for public T removeElement (T targetElement). Draw an example of removing an element to a BST.
4. Write the pseudocode for public void removeAllOccurrences (T targetElement).

Binary Trees 2015

September 29th, 2015

Binary Trees

Videos from mycodeschool.com

Binary Tree: Level Order Traversal

Binary Tree Traversal: Preorder, Inorder, Postorder

Delete a node from Binary Search Tree

Inorder Successor in a binary search tree

Check if a binary tree is binary search tree or not

Homework:

1. Draw the binary search tree that results from adding the following integers (34 45 3 87 65 32 1 12 17).

2. Look into the BinarySearchTreeADT in the book.

3. Read Implementing Binary Search Trees: With Links