CS62 - Spring 2011 - Lecture 13

  • video
       - http://www.youtube.com/watch?v=yX8yrOAjfKM (Matrix Windows XP)

  • admin
       - quiz Friday
       - assignment 4 out
          - a quick hint about how to tell if you're off the end
       - lab today: look at the two towers problem in the book (Section 8.7)

  • number representation in Java
       - As we've mentioned before, numbers are stored in binary
       - For example, the first few binary numbers are:
          0 = 0
          1 = 1
          2 = 10
          3 = 11
          4 = 100
          5 = 101
          6 = 110
          7 = 111
          8 = 1000
       - To calculate the value of a binary number:
          - digit/position i in the binary number represents a value of 2^i
             - this is similar to decimal number representation where digit/position i represents a value of 10^i
          - sum up the value of all of the digits where there is a 1
             - 101 = 2^0 + 2^2 = 5
             - 11011 = 2^0 + 2^1 + 2^3 + 2^4 = 1 + 2 + 8 + 16 = 27
             - 101010 = 2^1 + 2^3 + 2^5 = 2 + 8 + 32 = 42
          - In Java, there is another version of Integer.parseInt where we can pass a second parameter that is the "base" of the number we're trying to interpret. For binary, the base is 2.
             - System.out.println(Integer.parseInt("101010", 2));
                - 42
       - ints in Java are stored with 32 bits and longs with 64 bit
       - for now, we won't talk about how negative numbers are represented, but the basic idea is to use one of the bits to represent the sign and then the remaining bits for the number portion (it's a bit more complicated than this... Java uses a twos-complement representation for those who took cs52

  • More operators
       - we saw the ternary operator
       - Java has a number of "bitwise" operators that allow us to manipulate the individual bits of a number
       - bit shifting operators
          - << (left shift)
             - n << p shift the number n, p bits to the left, filling in the lower order bits with zeros
             - examples
                - 2 << 1 = 10 << 1 = 100 = 4
                - 5 << 1 = 101 << 1 = 1010 = 10
                - 6 << 3 = 110 << 4 = 110000 = 48
             - shifting the bits up one is equivalent to doubling the number
             - so, shifting the bits up p positions is equivalent to doubling the number p times, or multiplying by 2^p         - >> (right shift)
             - n >> p shift the number n, p bits to the right, throwing away the lower order bits
             - examples
                - 2 >> 1 = 10 >> 1 = 1
                - 5 >> 1 = 101 >> = 10 = 2
                - 13 >> 2 = 1101 >> 2 = 11 = 3
                - 14 >> 2 = 1110 >> 2 = 11 = 3
             - shifting the bits down one is equivalent to dividing the number by 2 and rounding down
             - so, shifting the bits down by p positions, is equivalent to divising by 2 p times, or dividing by 2^p and rounding down
          - be careful about overflow errors because of shifting too far to the left or right. Remember, an int is only 32 bits (and really 31 with a sign bit).

       - bitwise logical operators
          - we've seen && and || for booleans, there are equivalent operators on the bit level
          - show truth tables for "AND" and "OR"
          - the '&' and '|' operator perform bitwise "AND" and "OR" between two numbers
             - 14 & 3 = 1110 & 11 = 10 = 2
             - 14 | 3 = 1110 | 11 = 11 = 3
             - 12 & 5 = 1100 & 101 = 100 = 4
             - 12 | 5 = 1100 | 101 = 101 = 5
          - and, if you're curious '^' is the bitwise "XOR" operator
       
       - A few operations
          - how would you check if the last bit of an int num was a 1?
             - num & 1 == 1
          - how would you check if the nth bit of an int num was 1?
             - num >> n & 1 == 1

  • implementing a Queue
       - LinkedList
          - What kind do we need to use?
             - The easiest is to use a singly linked list
                - add elements to the tail/end
                - remove elements from the head/front
             - Could also use a doubly linked list (though why, if you don't need to)
       
       - ArrayList
          - Does it work well?
          - Array based
             - what if we wanted to implement it using an array, with the additional knowledge that we know the largest capacity required?
             - keep track of where our head is and where our tail is and have the data wrap around at the end of the array
                - always add at the tail
                - always remove from the head
             - is there an easy way to calculate indices?
                - use modular arithmetic!
                - if we want to increment the head, for example:
                   - instead of: headIndex++
                   - headIndex = (headIndex + 1) % data.length
             - look at ArrayQueue in StacksAndQueues code
       - http://java.sun.com/javase/6/docs/api/java/util/Queue.html

  • postfix notation (aka reverse polish notation)
       - http://xkcd.com/645/
       - what we normally think of as algebraic notation is called infix notation
          - the operators are in between the operands
             - 2 + 2
             - (1 + 3) * 4
       - postfix notation puts the operator at the end of the arguments, that is operators follow the operands
          - 3 4 +
          - 2 5 *
       - we can make more complex expression
          - (2 + 4) * 5
             - 2 4 + 5 *
          - (4 - 1) * (3 + 5)
             - 4 1 - 3 5 + *
          - notice that we no longer need parenthesis since there is no ambiguity
       - the algorithm to handle postfix notation is as follows:
          - Read the next token from input
          - If the token is a value
             - push it onto the stack
          - Otherwise, the token is an operator
             - It is known a priori that the operator takes n arguments
             - If there are fewer than n values on the stack
                - (Error) The user has not input sufficient values in the expression
             - Else, Pop the top n values from the stack
             - Evaluate the operator, with the values as arguments
             - Push the returned results, if any, back onto the stack
       - try a few:
          - 1 2 3 4 5 6 * + - / +
          - 2 3 + 5 * 2 2 2 * * +
          - 1 2 + 8 3 * -
          - 7 6 5 + 1 + + +
       - converting from infix to postfix
          - 5 + ((1 + 2) * 4) - 3
             - 1 2 + 4 * 5 + 3 -
             - 5 1 2 + 4 * 3 -
          - ((9 - 4) * 5)/2 + 4 * 5
             - 9 4 - 5 * 2 / 4 5 * +
             - 4 5 * 2 5 9 4 - * / +
          - many different ways to do it!
       - prefix notation is the reverse of postfix notation
          - + 2 3
          - + - 2 3 4