Title: Back to Phone Books
1Back to Phone Books
- When we looked at our simple array phone-book we
we saw that one way to speed it up would be
divide it into a lot of small arrays, one for
each initial letter. - Initial letters are not ideal since there are not
many of them and they are not equally
distributed. - Better is to use a number calculated from all the
letters in the string - called a hash code
2Hash Tables
- A hash table is a lookup table that uses an array
in which the location of each item is found by
using a function, called a hash function. - hash function converts a string into an integer.
- for example, could add up the numerical values of
the letters, or multiply them, or combine them in
some other way. - a good hash function is quick to calculate and
creates an even spread of values.
3Hash table collisions
- Any hash function will sometimes calculate the
same value for different strings. - called a collision
- Need some way to store multiple records with the
same hash code. - The easiest way is simply to use linked lists.
- results in an array of linked lists.
4Hash table example
- Alan and Fred have a hash value of 2
- Mary hashes to 6
- John hashes to 10
5public class HTable private int size private
Node table public HTable(int size)
this.size size table new
Nodesize for (int n 0 n tablen null private int
hash(String string) return
Math.abs(string.hashCode()) size
public void add(String name, String number)
int pos hash(name)
tablepos new Node(name, number,
tablepos) public String getNumber(String
name) int pos hash(name)
for (Node n tablepos n ! null n
n.next)? if (name.equals(n.name))?
return n.number
return null
6Notes
- We used the Java supplied hashCode() method as a
short-cut. - The code makes no attempt to cope with multiple
entries that have the same name. - A complete table would also need methods to
delete entries, return the number of entries and
so on.
7Hash table efficiency
- If the table size is the same as, or larger than,
the number of entries then average lookup takes
constant time. - Search time is the same however many records are
stored. - Generally, there is a trade-off between table
size and speed. - Hash tables are the usual way to implement a
lookup table where speed is very important.
8Recursion on linked lists
- All the linked list examples we have seen so far
use iteration when they need to work through the
nodes of a list (for example, to print nodes or
search for particular values). - We could alternatively use recursion.
- often neater than iteration
- a useful introduction to recursion on linked
structures - has hidden costs that you need to understand to
use it safely.
9Why use recursion
- For more complex linked data structures,
recursive methods are generally better than
iterative ones - easier to understand
- easier to write
- efficient
- Recursion on linked lists is useful learning
exercise.
10Example recursively printing nodes
- Our Linked list class had a print() method that
printed out the names and numbers from each of
the nodes of the list in order. - We could do this recursively instead.
// Print out the entries in the list, one per
line. public void print()? for
(Node n first n ! null n n.next)?
System.out.println(n.name " " n.number)
11 // Print out the entries in the list, //
one per line. public void printr()?
printr(first) // Recursively
print out the list starting at // start_node
private void printr(Node start_node)?
if (start_node null)?
return System.out.println(start_node.name
" "
start_node.number) printr(start_node.next
)
12Perspectives on recursion
- Sanity check
- How does it work?
- How can I create a recursive solution to my
problem? - What is going on behind the scenes?
- What are the costs?
13Recursion Sanity Check
- The recursive call should always be on a smaller
data structure than the current one. - There must always be a non-recursive option if
the data-structure is too small. - You often need a wrapper method to make the
recursive method accessible. - in this case, the no-parameter printr() method
14How to understand how a recursive method works
- Start off by working through what happens when it
is called with a null list (no recursion
happens). - Work through what happens when the list has only
one node. - Look at 2 nodes
- ...
15How to write a recursive method
- Suppose that you have an operation that you want
to perform on a linked list - Decide what to do if the list is empty.
- Imagine that you are looking at the first node of
a list and have already written the method so
that you can use it on the remaining list. - Think how to put together a working algorithm for
the whole list from your knowledge of the first
node and the results of calling the (still
unwritten) method for the rest of the list.
16Example print out list nodes in reverse order
- If the list is empty then the answer is to do
nothing. - Now imagine that you have written the method and
can use it on the remainder of the list after the
first node. - To print out all the nodes in reverse order you
call the the method to print the remaining nodes
in reverse order then print out the first node.
17Reverse printing code
// Recursively print out the list in reverse
// order. private void printr_rev(Node
start_node)? if (start_node
null)? return
printr_rev(start_node.next)
System.out.println(start_node.name
" " start_node.number)
18It seems too good to be true
- How could you do it without recursion?
- reverse the order of the list, print out the
nodes then reverse it again. - use an auxiliary data structure (a stack, say) to
store the values as you iterate forward through
the list. Then use the stored data to print out
the values once you have reached the end of the
list. - Both these are fiddly to program yet the
recursive print method does it just by reversing
the order of two lines of code.