Category Archives: Homework

Creating Data Types – Questions

Respond in complete sentences.

Be concise but do not copy and paste from the source. Use your own words.

Posted on 9/7/22

1. Name the basic elements of a data type.

2. What does API stand for and what would you need it for?

3. Where would you find the API for a class?

4. Name the Access modifiers.

5. What is an instance variable?

6. What is the difference between an instance variable and a local variable?

7. When would you use the “final” keyword?

8. What is the purpose of a constructor?

9. What are instance methods?

10. What are the 3 kinds of variables used in an instance method? What is their purpose?

11. What is a “Test client”?

Recursion: Fibonacci

Screen Shot 2014-09-16 at 9.07.52 PM

Classwork:
Use this class, Fibonacci to develop a better implementation of Fib(num) that saves computed values in an array. Compare the execution time of the original and the new version by choosing the value of num large enough to make a visible difference.

public class Fibonacci
{
   public static long Fib(num)
   {
     if (num == 0) return 0;
     if (num == 1) return 1;
     return Fib(num-1) + Fib(num-2);
   }
   
   public static void main(String [] args)
   {
      for (int i = 0; i < 100; i++)
          StdOut.println(i + " " + Fib(i);
   }
}

Homework:
Given the sequence of values of p and q that are computed when Euclid’s algorithm is used to compute the greatest common divisor of 105 and 24. Extend the code given below to develop a program EuclidGCD that takes two integers and computes their greatest common divisor, printing out the two arguments for each call on the recursive method. Use your program to compute the greatest common divisor of 1111111 and 1234567.

public static in gcd(int p, int q)
{
  if (q === 0) return p;
  int r = p % q;
  return gcd(q, r );
}

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.

 

The great tree-list recursion problem

Screen Shot 2015-02-09 at 12.56.51 AM

The great tree-list recursion problem. A binary search tree and a circular doubly linked list are conceptually built from the same type of nodes – a data field and two references to other nodes.

Given a binary search tree, rearrange the references so that it becomes a circular doubly-linked list (in sorted order). Nick Parlante describes this as one of the neatest recursive pointer problems ever devised.

Hint: create a circularly linked list A from the left subtree, a circularly linked list B from the right subtree, and make the root a one-node circularly linked list. Then merge the three lists.

Screen Shot 2015-02-22 at 1.50.19 PM

Balanced Trees Red-Black – Web Exercises

Screen Shot 2015-02-27 at 7.44.59 AM

Balanced Trees
Red-Black trees
Screen Shot 2015-03-03 at 7.41.28 AM

Web Exercises

  1. Given a sorted sequence of keys, describe how to construct a red-black BST that contains them in linear time.
  2. Suppose that you do a search in a red-black BST that terminates unsuccessfully after following 20 links from the root. Fill in the blanks below with the best (integer) bounds that you can infer from this fact about any unsuccessful search
    • Must follow at least ______ links from the root
    • Need follow at most _______ links from the root
  3. With 1 bit per node we can represent 2-, 3-, and 4-nodes. How many bits would we need to represent 5-, 6-, 7-, and 8-nodes.
  4. Substring reversing. Given a string of length N, support the following operations: select(i) = get the ith character, and reverse(i, j) = reverse the substring from i to j.Solution sketch. Maintain the string in a balanced search tree, where each node records the subtree count and a reverse bit (that interchanges the role of the left and right children if there are an odd number of reverse bits on the path from the root to the node). To implement select(i), do a binary search starting at the root, using the subtree counts and reverse bits. To implement reverse(i, j), split the BST at select(i) and select(j) to form three BSTs, reverse the bit of the middle BST, and join them back together using a join operation. Maintain the subtree counts and reverse bits when rotating.
  5. Memory of a BST. What is the memory usage of a BST and RedBlackBST and TreeMap?Solution. MemoryOfBSTs.java.
  6. Randomized BST. Program RandomizedBST.java implements a randomized BST, including deletion. Expected O(log N) performance per operations. Expectation depends only on the randomness in the algorithm; it does not depend on the input distribution. Must store subtree count field in each node; generates O(log N) random numbers per insert.Proposition. Tree has same distribution as if the keys were inserted in random order.
  7. Join. Write a function that takes two randomized BSTs as input and returns a third randomized BST which contains the union of the elements in the two BSTs. Assume no duplicates.
  8. Splay BST. Program SplayBST.java implements a splay tree.
  9. Randomized queue. Implement a RandomizedQueue.java so that all operations take logarithmic time in the worst case.
  10. Red-black BST with many updates. When performing a put() with a key that is already in a red-black BST, our RedBlackBST.java performs many unnecessary calls to isRed() and size(). Optimize the code so that these calls are skipped in such situations.

Red-Black Trees – BSTs – Exercises

Screen Shot 2015-02-27 at 7.44.59 AM

Balanced Trees
Red-Black trees
Screen Shot 2015-03-03 at 7.41.28 AM

Exercises

  1. Which of the follow are legal balanced red-black BSTs?
    Legal balanced red-black BSTs
    Solution. (iii) and (iv) only. (i) is not balanced, (ii) is not in symmetric order or balanced.
  2. True or false: If you insert keys in increasing order into a red-black BST, the tree height is monotonically increasing.Solution. True, see the next question.
  3. Draw the red-black BST that results when you insert letters A through K in order into an initially empty red-black BST. Then, describe what happens in general when red-black BSTs are built by inserting keys in ascending order.

    Insert 255 keys in a red-black BST in ascending order.

    Your browser can not display this movie.
    Be sure that Javascript is enabled and that you have Flash 9.0.124 or better.

  4. Answer the previous two questions for the case when the keys are inserted in descending order.Solution. False.

    Insert 255 keys in a red-black BST in descending order.

    Your browser can not display this movie.
    Be sure that Javascript is enabled and that you have Flash 9.0.124 or better.

  5. Create a test client TestRedBlackBST.java.

Balanced Trees Red-Black trees

Screen Shot 2015-02-27 at 7.44.59 AM

Balanced Trees
Red-Black BST
Screen Shot 2015-03-03 at 7.41.28 AM

The insertion algorithm for 2-3 trees just described is not difficult to understand. We consider a simple representation known as a red-black BST that leads to a natural implementation.

  • Encoding 3-nodes. The basic idea behind red-black BSTs is to encode 2-3 trees by starting with standard BSTs (which are made up of 2-nodes) and adding extra information to encode 3-nodes. We think of the links as being of two different types: red links, which bind together two 2-nodes to represent 3-nodes, and black links, which bind together the 2-3 tree. Specifically, we represent 3-nodes as two 2-nodes connected by a single red link that leans left. We refer to BSTs that represent 2-3 trees in this way as red-black BSTs.One advantage of using such a representation is that it allows us to use our get() code for standard BST search without modification.

    Encoding a 3-node in a red-black BST
  • A 1-1 correspondence. Given any 2-3 tree, we can immediately derive a corresponding red-black BST, just by converting each node as specified. Conversely, if we draw the red links horizontally in a red-black BST, all of the null links are the same distance from the root, and if we then collapse together the nodes connected by red links, the result is a 2-3 tree.
    1-1 correspondence between left-leaning
red-black BSTs and 2-3 trees
  • Color representation. Since each node is pointed to by precisely one link (from its parent), we encode the color of links in nodes, by adding a boolean instance variable color to our Node data type, which is true if the link from the parent is red and false if it is black. By convention, null links are black.
    Color representation in a red-black BST
  • Rotations. The implementation that we will consider might allow right-leaning red links or two red-links in a row during an operation, but it always corrects these conditions before completion, through judicious use of an operation called rotation that switches orientation of red links. First, suppose that we have a right-leaning red link that needs to be rotated to lean to the left. This operation is called a left rotation. Implementing a right rotation that converts a left-leaning red link to a right-leaning one amounts to the same code, with left and right interchanged.
  • Flipping colors. The implementation that we will consider might also allow a black parent to have two red children. The color flip operation flips the colors of the the two red children to black and the color of the black parent to red.
    Left rotation in a red-black BST Right rotation in a red-black BST Color flip in a red-black BST
  • Insert into a single 2-node.
  • Insert into a 2-node at the bottom.
  • Insert into a tree with two keys (in a 3-node).
  • Keeping the root black.
  • Insert into a 3-node at the bottom.
  • Passing a red link up the tree.

Implementation.

Program RedBlackBST.java implements a left-leaning red-black BST. Program RedBlackLiteBST.java is a simpler version that only implement put, get, and contains.

Red-black BST construction

Deletion.

Proposition.

The height of a red-blackBST with N nodes is no more than 2 lg N.

Proposition.

In a red-black BST, the following operations take logarithmic time in the worst case: search, insertion, finding the minimum, finding the maximum, floor, ceiling, rank, select, delete the minimum, delete the maximum, delete, and range count.

Property.

The average length of a path from the root to a node in a red-black BST with N nodes is ~1.00 lg N.

Visualization.

Insert 255 keys in a red-black BST in random order.

Your browser can not display this movie.
Be sure that Javascript is enabled and that you have Flash 9.0.124 or better.

Exercises

  1. Which of the follow are legal balanced red-black BSTs?
    Legal balanced red-black BSTs
    Solution. (iii) and (iv) only. (i) is not balanced, (ii) is not in symmetric order or balanced.
  2. True or false: If you insert keys in increasing order into a red-black BST, the tree height is monotonically increasing.Solution. True, see the next question.
  3. Draw the red-black BST that results when you insert letters A through K in order into an initially empty red-black BST. Then, describe what happens in general when red-black BSTs are built by inserting keys in ascending order.

    Insert 255 keys in a red-black BST in ascending order.

    Your browser can not display this movie.
    Be sure that Javascript is enabled and that you have Flash 9.0.124 or better.

  4. Answer the previous two questions for the case when the keys are inserted in descending order.Solution. False.

    Insert 255 keys in a red-black BST in descending order.

    Your browser can not display this movie.
    Be sure that Javascript is enabled and that you have Flash 9.0.124 or better.

  5. Create a test client TestRedBlackBST.java.

Creative Problems

  1. Certification. Add to RedBlackBST.java a method is23() to check that no node is connected to two red links and that there are no right-leaning red links. Add a method isBalanced() to check that all paths from the root to a null link have the same number of black links. Combine these methods with isBST() to create a method isRedBlackBST() that checks that the tree is a BST and that it satisfies these two conditions.
  2. Fundamental theorem of rotations. Show that any BST can be transformed into any other BST on the same set of keys by a sequence of left and right rotations.Solution sketch: rotate the smallest key in the first BST to the root along the leftward spine; then recur with the resulting right subtree until you have a tree of height N (with every left link null). Do the same with the second BST. Remark: it is unknown whether there exists a polynomial-time algorithm for determining the minimum number of rotations needed to transform one BST into the other (even though the rotation distance is at most 2N – 6 for BSTs with at least 11 nodes).
  3. Delete the minimum. Implement the deleteMin() operation for RedBlackBST.java by maintaining the correspondence with the transformations given in the text for moving down the left spine of the tree while maintaining the invariant that the current node is not a 2-node.
  4. Delete the maximum. Implement the deleteMax() operation for RedBlackBST.java. Note that the transformations involved differ slightly from those in the previous exercise because red links are left-leaning.
  5. Delete. Implement the delete() operation for RedBlackBST.java, combining the methods of the previous two exercises with the delete()operation for BSTs.

Web Exercises

  1. Given a sorted sequence of keys, describe how to construct a red-black BST that contains them in linear time.
  2. Suppose that you do a search in a red-black BST that terminates unsuccessfully after following 20 links from the root. Fill in the blanks below with the best (integer) bounds that you can infer from this fact about any unsuccessful search
    • Must follow at least ______ links from the root
    • Need follow at most _______ links from the root
  3. With 1 bit per node we can represent 2-, 3-, and 4-nodes. How many bits would we need to represent 5-, 6-, 7-, and 8-nodes.
  4. Substring reversing. Given a string of length N, support the following operations: select(i) = get the ith character, and reverse(i, j) = reverse the substring from i to j.Solution sketch. Maintain the string in a balanced search tree, where each node records the subtree count and a reverse bit (that interchanges the role of the left and right children if there are an odd number of reverse bits on the path from the root to the node). To implement select(i), do a binary search starting at the root, using the subtree counts and reverse bits. To implement reverse(i, j), split the BST at select(i) and select(j) to form three BSTs, reverse the bit of the middle BST, and join them back together using a join operation. Maintain the subtree counts and reverse bits when rotating.
  5. Memory of a BST. What is the memory usage of a BST and RedBlackBST and TreeMap?Solution. MemoryOfBSTs.java.
  6. Randomized BST. Program RandomizedBST.java implements a randomized BST, including deletion. Expected O(log N) performance per operations. Expectation depends only on the randomness in the algorithm; it does not depend on the input distribution. Must store subtree count field in each node; generates O(log N) random numbers per insert.Proposition. Tree has same distribution as if the keys were inserted in random order.
  7. Join. Write a function that takes two randomized BSTs as input and returns a third randomized BST which contains the union of the elements in the two BSTs. Assume no duplicates.
  8. Splay BST. Program SplayBST.java implements a splay tree.
  9. Randomized queue. Implement a RandomizedQueue.java so that all operations take logarithmic time in the worst case.
  10. Red-black BST with many updates. When performing a put() with a key that is already in a red-black BST, our RedBlackBST.java performs many unnecessary calls to isRed() and size(). Optimize the code so that these calls are skipped in such situations.

BSTs – 2-3 search trees

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.

2-3 search trees.

The primary step to get the flexibility that we need to guarantee balance in search trees is to allow the nodes in our trees to hold more than one key.

Definition.

2-3 search tree is a tree that either is empty or:

  • 2-node, with one key (and associated value) and two links, a left link to a 2-3 search tree with smaller keys, and a right link to a 2-3 search tree with larger keys
  • 3-node, with two keys (and associated values) and three links, a left link to a 2-3 search tree with smaller keys, a middle link to a 2-3 search tree with keys between the node’s keys and a right link to a 2-3 search tree with larger keys.

Anatomy of a 2-3 tree
perfectly balanced 2-3 search tree (or 2-3 tree for short) is one whose null links are all the same distance from the root.

  • Search. To determine whether a key is in a 2-3 tree, we compare it against the keys at the root: If it is equal to any of them, we have a search hit; otherwise, we follow the link from the root to the subtree corresponding to the interval of key values that could contain the search key, and then recursively search in that subtree.
    Search in a 2-3 tree
  • Insert into a 2-node. To insert a new node in a 2-3 tree, we might do an unsuccessful search and then hook on the node at the bottom, as we did with BSTs, but the new tree would not remain perfectly balanced. It is easy to maintain perfect balance if the node at which the search terminates is a 2-node: We just replace the node with a 3-node containing its key and the new key to be inserted.
    Insert into a 2-node in a 2-3 tree
  • Insert into a tree consisting of a single 3-node. Suppose that we want to insert into a tiny 2-3 tree consisting of just a single 3-node. Such a tree has two keys, but no room for a new key in its one node. To be able to perform the insertion, we temporarily put the new key into a 4-node, a natural extension of our node type that has three keys and four links. Creating the 4-node is convenient because it is easy to convert it into a 2-3 tree made up of three 2-nodes, one with the middle key (at the root), one with the smallest of the three keys (pointed to by the left link of the root), and one with the largest of the three keys (pointed to by the right link of the root).
    Insert into a 2-3 tree consisting of a single 3-node
  • Insert into a 3-node whose parent is a 2-node. Suppose that the search ends at a 3-node at the bottom whose parent is a 2-node. In this case, we can still make room for the new key while maintaining perfect balance in the tree, by making a temporary 4-node as just described, then splitting the 4-node as just described, but then, instead of creating a new node to hold the middle key, moving the middle key to the nodes parent.
    Insert in a 2-3 tree into a 3-node whose parent is a 2-node
  • Insert into a 3-node whose parent is a 3-node. Now suppose that the search ends at a node whose parent is a 3-node. Again, we make a temporary 4-node as just described, then split it and insert its middle key into the parent. The parent was a 3-node, so we replace it with a temporary new 4-node containing the middle key from the 4-node split. Then, we perform precisely the same transformation on that node. That is we split the new 4-node and insert its middle key into its parent. Extending to the general case is clear: we continue up the tree, splitting 4-nodes and inserting their middle keys in their parents until reaching a 2-node, which we replace with a 3-node that does not to be further split, or until reaching a 3-node at the root.
    Insert in a 2-3 tree into a 3-node whose parent is a 3-node
  • Splitting the root. If we have 3-nodes along the whole path from the insertion point to the root, we end up with a temporary 4-node at the root. In this case we split the temporary 4-node into three 2-nodes.
    Splitting the root in a 2-3 tree
  • Local transformations. The basis of the 2-3 tree insertion algorithm is that all of these transformations are purely local: No part of the 2-3 tree needs to be examined or modified other than the specified nodes and links. The number of links changed for each transformation is bounded by a small constant. Each of the transformations passes up one of the keys from a 4-node to that nodes parent in the tree, and then restructures links accordingly, without touching any other part of the tree.
  • Global properties. These local transformations preserve the global properties that the tree is ordered and balanced: the number of links on the path from the root to any null link is the same.

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.

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