Date: Wed, 27 Oct 1999 11:20:55 -0400 (EDT)
From: Archisman Rudra 
Subject: HW3 Soln-s


Sample Solution to HW3 : Archi


1. Let m be the input size on the new machine.

	Then, because both machines take the same time T,

	T = T(n)
	and
	T = (1/64) T(m)
  i.e.
	T(m) = 64 * T(n)

  We solve this in the various cases:

  (a)	T(n) = 3 * 2^n.

	i.e., 3 * 2^m = 64 * 3 * 2^n
	or,   2^m = 64 * 2^n
	or,   m = n + 6 (after taking lg)

  (b)	T(n) = n^2.

	ie, m^2 = 64 * n^2,
	or, m = 8 * n (Taking square roots)

  (c)	T(n) = 8 * n.

	ie, 8 * m = 64 * 8 * n
	or  m = 64 * n


2.	To show that log (n!) = Theta (n log n)


  (a)      log (n!) = log 1 + log 2 + ... + log n

		  <= log n + log n + ... + log n       (n terms)
		  =  n log n.

  This shows that log (n!) = O (n log n)


  (b)      log (n!) = log 1 + log 2 + ... + log n
		  >= log (n/2) + log (n/2 + 1) + ... + log n     (about (n/2) terms)
		  >= log (n/2) + log (n/2) + ... + log (n/2)     (n/2 terms (about))
		  = (n/2) log (n/2)


	We will show that (n/2) log (n/2) >= (1/4) n log n,  for n >= 4


           (n/2) log (n/2)   = (1/2) n log n - (1/2) n

        n >= 4 = 2^2

	=> log n >= 2
	=> n * log n >= 2 * n    (since n >= 4 > 0)
	=> (1/4) n log n >= (1/2) n
	=> -(1/2) n >= -(1/4) n * log n
	=> (1/2) n * log n - (1/2) n     >= (1/2) n * log n - (1/4) n * log n
					 = (1/4) n * log n.

	i.e,
		log (n!) >= (n/2) log (n/2) >= (1/4) n * log n,    for n >= 4.


	From (a) and (b), we conclude 	log (n!) = Omega (n * log n)

3.


  (a)    9     9      9      etc.: Final tree:           9
              /      /                                 /   \
             7      7                                 7      12
                   /                                 / \    /   \
                  2                                 2   8  10    16
                                                   / \      \    /
                                                  1   5     11  13


  (b)      9 7 2 1 5 8 12 10 11 16 13

  (c)      1 2 5 7 8 9 10 11 12 13 16

  (d)      1 5 2 8 7 11 10 13 16 12 9

  (e)            9
               /   \
              7      13
             / \    /   \
            2   8  10    16
           / \      \
          1   5     11

	assuming we use the immediate successor rule.

4.

  Initial Array: 
	9, 7, 2, 8, 12, 5, 1, 16, 10, 13. 11  (No need to write this)

  The initial config is:

                  9
               /    \
              7       2
            /  \     /  \
           8    12  5    1
          / \   / \
         16 10 13 11


  After 3 siftdowns:

                  9
               /    \
              7       5
            /  \     /  \
          16    13  2    1
          / \   / \
         8  10 12 11

  One more siftdown:

                  9
               /    \
             16       5
            /  \     /  \
          10    13  2    1
          / \   / \
         8   7 12 11

  Final tree:

                 16
               /    \
             13       5
            /  \     /  \
          10    12  2    1
          / \   / \
         8   7 9  11

(b) RemoveMax removes the maximum element (16).

                 11
               /    \
             13       5
            /  \     /  \
          10    12  2    1
          / \   /
         8   7 9


   And after siftdown to rebuild the heap:


                 13
               /    \
             12       5
            /  \     /  \
          10    11  2    1
          / \   /
         8   7 9


5. Programming part:

/* file: myNode.java
 * Basic Algorithms, Fall 1999, Yap
 *
 * HW3 problem:
 *  It declares an interface called "nodeInt"
 *  and a class myNode that implements nodeInt.
 *  The interface nodeInt is a variation taken from hw2.
 *
 */

import java.io.*;			// to use DataInputStream

//==================================================
// nodeInt:
//	this interface is a slight variation of what
//	you did for hw2.  In particular, we now assume
//	"item" is a String rather than a general object.
//
// 	For comparisons, you use "S1.compareTo(S2)" as
//	explained under "merge" below.
//==================================================

interface nodeInt {

  //==================================================
  // basic methods  (as in hw2)
  //==================================================

  public void setItem(String i);
  public void setNext(nodeInt n);	// next = n
  public nodeInt getNext();
  public String getItem();
  public void printItem();
  public void print();

  //==================================================
  // methods for File I/O  (as in hw2)
  //==================================================

  public int readString(DataInputStream dis);
      // NOTE: on Unix/Linux, end-of-line is indicated by "\n"
      // On Windows, end-of-line is indicated by "\r\n".
  public int readFromFile(String fn);
} // nodeInt


public class myNode implements nodeInt {

  //==================================================
  // variables
  //==================================================
  private String item;
  private nodeInt next;

  //==================================================
  // constructors
  //==================================================
  myNode() {// fill in your code;
     this(null, null);
  }
  myNode(String e, nodeInt n) {// fill in your code;
        item = e;
        next = n;
  }

  //==================================================
  // basic methods
  // 	-- remove "abstract" and fill in code
  //==================================================

  public void setItem(String i)
    { item = i; }
    //  public abstract void setItem(nodeInt n);
  public void setNext(nodeInt n)
    { next = n; }
  public nodeInt getNext()
    { return next;}
  public String getItem()
    { return item; }
  public void printItem()
    { System.out.print(item); }
  public void print()
    {
       myNode pointer = this;
       while (pointer != null) {
          pointer.printItem();
          System.out.print("\n");
          pointer = (myNode) pointer.getNext();
       }
    }

  public int readString(DataInputStream dis)
  {
	byte[] cc = new byte[100];
	byte  c;
	boolean EOF_FLAG = false;
	int i = 0;
	try{
	  while( !EOF_FLAG )
	  {
	    c = dis.readByte();
	    if (c == '\n')
	    {
	      EOF_FLAG = true;
	      //     dis.readByte();	   // following '\r' is '\n',
	    }			   //    which we just discard
	    else { cc[i] = c; i++; }
	  }
	} catch(Exception e) { item = null; return -1; };
	item = new String(cc, 0, i);
	return i;
  } //readString

  public int readFromFile(String fn)
    // returns the number of nodes in list
    // the first node in the read-in list is "this"
    // if the returned value is <0, error in opening files
  {
        FileInputStream is = null;
        DataInputStream dis = null;

        try {
                is = new FileInputStream(fn);
                dis = new DataInputStream(is); 
        } catch (Exception e) {
                System.out.println("Fail to Open");
                return -1;
        }

        int count = 0;
        myNode curr = new myNode();
        myNode last = this;

        if (curr.readString(dis) < 0) 
        { return -1;
        } else
        { ++count;
          last.setItem(curr.getItem());
          curr = new myNode();
          while (curr.readString(dis) >= 0)  // allow 0 length item
          { last.setNext(curr);
            last = (myNode) last.getNext();
            curr = new myNode();
            ++count;
          }
        }
        return count;
  } //readFromFile

  //==================================================
  // sort:
  //	implements merge sort of a list of strings
  //	in increasing order.
  //	Returns the nodeInt that is the start of the
  //	sorted list.
  //==================================================
  public nodeInt sort()
    {myNode even, odd;


         if(this == null)
              return null;
         if(this.getNext() == null)
              return this;

         even = (myNode) split ();
         odd = this;

         return merge (even.sort(), odd.sort());


    }
  //==================================================
  // split:
  //	takes *this* list, and splits it into
  //	an odd sublist and an even sublists.
  //	The value of *this* is the first node in the odd
  //	and the returned value is the first node of the
  //	even sublist.  [Note: the even sublist has length
  //	equal to, or one less than, the length of odd sublist.]
  //	
  //    Assume *this* has at least one node.
  //    CAREFUL: the input list must be NULL terminated.
  //==================================================

  public nodeInt split()
    {
       nodeInt oddPointer, evenPointer, retVal, temPtr;
       boolean done;

       if (this == null)
          return null;

       oddPointer = this;
       retVal = evenPointer = this.getNext();
       done = false;

       while (!done) {
	   if (evenPointer != null){
              temPtr = evenPointer.getNext();
              oddPointer.setNext(temPtr);
              oddPointer = temPtr;
           }
           else {
              done = true;
              continue;
           }
	   if (oddPointer != null){
              temPtr = oddPointer.getNext();
              evenPointer.setNext(temPtr);
              evenPointer = temPtr;
           }
           else done = true;
       }
       return retVal;
    }

  //==================================================
  // merge(L, L1)
  // 	-- assumes L and L1 not null
  //	-- returns the first node of the merged list.
  //	-- To compare, you will need to use the "compareTo"
  //	   method for Strings.   E.g.
  //
  //	   	String s1 = "111";
  //	   	String s2 = "222";
  //	   	if (s1.compareTo(s2) < 0) 
  //		   System.out.println("s1 is smaller than s2");
  //		else
  //		   System.out.println("s1 is not smaller than s2");
  //
  //	-- In fact, (s1.compareTo(s2) == 0) if and only if
  //	   the two strings are equal.
  //==================================================

  public static myNode merge(nodeInt L, nodeInt L1)
	{

        myNode l, l1;

	// dummy implementation !
        if (L == null)
           return (myNode)L1;
        if (L1 == null)
           return (myNode) L;

        l1 = (myNode) L1;
        l  = (myNode) L;

        if(l.item.compareTo(l1.item) < 0){
             L.setNext( merge (L.getNext(), L1));
             return (myNode) L;
        }
        else {
             L1.setNext( merge (L, L1.getNext()));
             return (myNode) L1;
	}

	};

  //==================================================
  public static void main(String[] args)
  {
      /* THIS IS THE REQUIRED BODY:*/
    String fn = "input.0";		// default file
    if (args.length > 0) fn = args[0];  // if file is specified

    myNode N = new myNode(); 
    int n = N.readFromFile(fn);  	// create a list from file "fn"
    System.out.println("....INPUT LIST:");
    N.print();
    N = (myNode)N.sort();

    System.out.println("....SORTED LIST:");
    N.print();

  }

}  //Node class