CS307 Spring 2008 Final Solution and Grading Criteria. Grading acronyms: ABA - Answer by Accident AIOBE - Array Index out of Bounds Exception may occur BOD - Benefit of the Doubt. Not certain code works, but, can't prove otherwise ECF - Error carried forward. Gacky or Gack - Code very hard to understand even though it works or solution is not elegant. (Generally no points off for this.) GCE - Gross Conceptual Error. Did not answer the question asked or showed fundamental misunderstanding NAP - No answer provided. No answer given on test NN - Not necessary. Code is unneeded. NPE - Null Pointer Exception may occur OBOE - Off by one error. Calculation is off by one. 1. 1.5 points per question. No partial credit. On Big O question if answer is O(N) N is acceptable. No constants or extra terms on Big O. For example if answer is O(N) then O(4N) is counter wrong as is O(N + 10). A. 7 / 0 / \ -5 5 / 3 B. CAKAJSEM C. KJASACME D. JSAKAMEC E. No F. 4 G. O(logN) H. The declared type of the get method for the raw ArrayList is Object. Object does not have a charAt method. I. There is an infinite loop if the target is found due to the short circuiting of the or (||). J. THAAHT K. O(N) L. O(logN) M. O(N) N. O(N) O. O(N^2) P. O(N^2) Q. 16 seconds R. Sort the data. Work if sort first = 1*10^6 * log base 2 1*10^6 + 10,000*log base 2 1*10^6 = 1*10^6 * 20 + 10,000 * 20 = 20,000,000 + 200,000 = 20,200,000 Work without sorting = 10,0000 * 500,0000 = 1 * 10^4 * 5 * 10^5 = 5 * 10^9 = 5,000,000,000 5,000,000,000 >> 20,200,000 S. 11 bits (12 accepted) T. 150 2A: public HuffmanTree( Map code ){ // Assume assertions checked here. // Complete the method below. Iterator it = code.keySet().iterator(); char ch; while(it.hasNext()){ ch = it.next(); addCharacter(ch, code.get(ch)); } } version that uses enhanced for loop public HuffmanTree( Map code ){ for( char ch : code.keySet() ) addCharacter(ch, code.get(ch)); } 2B. Recursive solution: private void addCharacter(char ch, String chCode){ root = addHelper(ch, chCode, root); } private HuffNode addHelper(char ch, String chCode, HuffNode n) { if( chCode.length() == 0 ) n = new HuffNode(ch); else{ if( n == null ) n = new HuffNode(); if( chCode.charAt(0) == '0' ) n.left = addHelper(ch, chCode.substring(1), n.getLeft() ); else n.right = addHelper(ch, chCode.substring(1), n.getRight() ); } return n; } iterative solution: private void addCharacter(char ch, String chCode){ if( root = null ) root = new HuffNode(); // some did this in part A. Much cleaner that way. HuffNode temp = root; for(int i = 0; i < chCode.length() - 1; i++){ if( chCode.charAt(i) == '0' ){ if( temp.getLeft() == null ) temp.setLeft( new HuffNode() ); temp = temp.getLeft(); } else { if( temp.getRight() == null ) temp.setRight( new HuffNode() ); temp = temp.getRight(); } } if( chCode.charAt( chCode.length() - 1 ) == '0' ) temp.setLeft( new HuffNode(ch) ); else temp.setRight( new HuffNode(ch) ); } 3. Lots of special cases. public boolean remove(Object obj){ assert obj != null; int oldSize = size; // only need to remove if size greater than 0 if( size > 0 ){ // special case data in first node? if( first.getData().equals(obj) ){ size--; first.decrementCount(); if( first.getCount() == 0 ){ if( size == 0 ) first == null; else{ first = first.getNext(); first.setPrev( first.getPrev().getPrev() ); first.getPrev().setNext(first) } } } else { // general case Node temp = first.getNext(); while( temp != first && !temp.getData().equals( obj ) ) temp = temp.getNext(); //did I find it? if( temp != first ){ size--; temp.decrementCount(); if( temp.getCount() == 0 ){ temp.getPrev().setNext( temp.getNext() ); temp.getNext().setPrev( temp.getPrev() ); } } } } return oldSize != size; } Alternate version with helper method to remove node once found. Avoids some repeated code from special cases. public boolean remove(Object obj){ int oldSize = size; if( size > 0 ){ if( first.getData().equals( obj ) ) removeHelp( first ); else{ Node temp = first.getNext(); while( temp != first && !temp.getData().equals( obj ) ) temp = temp.getNext(); if( temp != first ) removeHelp( temp ); } } return oldSize != size; } private void removeHelp(Node n){ size--; n.decrementCount(); if( n.getCount() == 0 ){ if( size == 0 ) first = null; else{ if( temp == first ) first = first.getNext(); temp.getPrev().setNext( temp.getNext() ); temp.getNext().setPrev( temp.getPrev() ); } } } 4. Most solutions don't need to worry about getting into a cycle becuase of the limitation on the number of steps. Iterative version. public boolean pathExists(int startNode, int tgtNode, int steps){ boolean found = false; if( startNode > 0 && tgtNode > 0 && startNode < adjacencyMatrix.length && tgtNode < adjacencyMatrix.length ){ Queue q = new Queue(); q.enqueue(startNode); int node; while( !found && steps > 0 && !q.isEmpty() ){ steps--; node = q.dequeue(); for(int i = 0; i < adjacencyMatrix.length; i++){ if( adjacencyMatrix[node][i] ){ found = i == tgtNode; q.enqueue(i); } } } } return found; } Recursive version public boolean pathExists(int startNode, int tgtNode, int steps){ // base case out of bounds. if( startNode > 0 && tgtNode > 0 && startNode < adjacencyMatrix.length && tgtNode < adjacencyMatrix.length ) return false; // base case: no more steps allowed else if( steps == 0 ) return false; // base case found it! else if( adjacencyMatrix[startNode][tgtNode] ) return true; else{ // recursive case. check links. for(int col = 0; col < adjacencyMatrix.length; col++) if( adjacencyMatrix[startNode][col] && pathExists( col, tgtNode, steps - 1 ) return true; } // never found a path return false; } 5. public static boolean topAndBottonEqual(Stack st){ if( st.isEmpty() ) return false; // remember top item Object top = st.top(); Stack temp = new Stack(); while( !st.isEmpty() ) temp.push( st.pop() ); // remember bottom item Object bottom = temp.top(); // restore stack while( !temp.isEmpty() ) st.push( temp.pop() ); return top.equals( bottom ); }