Java Basics and Union-Find
Basics
-
Java basics Data types; Abstract data types; Application programming interface (API); The following list contains some points need to pay attention.
-
Interface inheritance: subtyping:
-
comparison:
java.lang.Comparable: compareTo(); java.util.Comparator: compare();
-
iteration:
java.lang.Iterable: iterator(); java.util.Iterator: hasNext(), next(), remove()
-
Implementation inheritance: subclassing:
-
Class getClass()
what class is this object? -
String toString()
string representation of this object. -
boolean equals(Object that)
is the object equal to that? -
int hashCode()
hash code for this object. -
Equality
-
If we test equality with (a == b) where a and b are reference variables of the same type, we are testing whether they have the same identity: whether the references are equal. Typical clients would rather be able to test whether the data-type values (object state) are the same. Every Java type inherits the method equals() from Object. Java provides natural implementations both for standard types such as Integer, Double, and String and for more complicated types such as java.io.File and java.net.URL. When we define our own data types we need to override equals(). Java’s convention is that equals() must be an equivalence relation:
Reflexive: x.equals(x) is true.
Symmetric: x.equals(y) is true if and only if y.equals(x) is true.
Transitive: if x.equals(y) and y.equals(z) are true, then so is x.equals(z).
In addition, it must take an Object as argument and satisfy the following properties.
Consistent: multiple invocations of x.equals(y) consistently return the same value, provided neither object is modified.
Not null: x.equals(null) returns false.
Adhering to these Java conventions can be tricky, as illustrated for Date.java and Transaction.java.
/** * Compares this date to the specified date. * * @param other the other date * @return {@code true} if this date equals {@code other}; {@code false} otherwise */ @Override public boolean equals(Object other) { if (other == this) return true; if (other == null) return false; if (other.getClass() != this.getClass()) return false; Date that = (Date) other; return (this.month == that.month) && (this.day == that.day) && (this.year == that.year); }
-
Wrapper types
boolean -> Boolean
,byte -> Byte
,char -> Character
,double -> Double
,int -> Integer
, long, short, float… -
Immutability:
Immutable objects:String
is immutable, Primitive wrappers (Integer
,Long
,Short
,Double
,Float
,Character
,Byte
,Boolean
) are also all immutable. Reference types cannot be made immutable just by using thefinal
keyword.final
only prevents reassignment.
Difference betweenfinal
andimmutable
-
-
Bags, Queues, and Stacks
- Resizing array implementation
- Linked Lists implementation.
-
Analysis of algorithms
- Big O notation, Big Theta notation …
Case study: Union-Find
-
array implementation, Quick Find (QF) QuickFindUF.java
maintains the invariant that p and q are connected if and only if id[p] is equal to id[q]. In other words, all sites in a component must have the same value in id[].
Union:
O(N)
. Find:O(1)
. Construct:O(N)
. Takes N^2 array access to process sequence of N union commands on N objects./* main function of QuickFindUF.java */ public class QuickFindUF { private int[] id; // id[i] = component identifier of i private int count; // number of components public QuickFindUF(int n) { count = n; id = new int[n]; for (int i = 0; i < n; i++){ id[i] = i; } } public int find(int p) { return id[p]; } public boolean connected(int p, int q) { return id[p] == id[q]; } public void union(int p, int q) { int pID = id[p]; int qID = id[q]; if (pID == qID) return; for (int i = 1; i < n; i++) { if (id[i] = pID) id[i] = qID; } count--; } }
-
Quick-union. QuickUnionUF.java
private int[] parent; public QuickUnionUF(int n) { count = n; parent = new int[n]; for (int i = 0; i < n; i++) { parent[i] = i; } } public int find(int p) { while (p != parent[p]) p = parent[p]; return p; } public boolean connected(int p, int q) { return find(p) == find(q); } public void union(int p, int q) { int rootP = find(p); int rootQ = find(q); if (rootP == rootQ) return; parent[rootP] = rootQ; count--; }
-
Weighted Quick Union. Rather than arbitrarily connecting the second tree to the first for union() in the quick-union algorithm, we keep track of the size of each tree and always connect the smaller tree to the larger. Program WeightedQuickUnionUF.java implements this approach.
Find and Union bothO(lgN)
/* find and connected the same with QuickUnionUF.java An extra array size[], size[i] was used to identify the number of elements in subtree rooted at i */ public WeightedQuickUnionUF() { count = n; parent = new int[n]; size = new int[n]; for (int i = 0; i < n; i++) { parent[i] = i; size[i] = 1; // initial size is 1. } } public void union(int p, int q) { int rootP = find(p); int rootQ = find(q); if (rootP == rootQ) return; // make smaller root point to larger root if (size(rootP) < size(rootQ)) { parent[rootP] = rootQ; size[rootQ] += size[rootP]; } else { parent[rootQ] = rootP; size[rootP] += size[rootQ]; } count--; }
-
Weighted quick-union with path compression
/* Simple one-pass variant: Make every other node in path point to its grandparent (thereby halving path length) Keep tree almost completely flat in practice. */ private int root(int i) { while (i != id[i]) { id[i] = id[id[i]]; i = id[i]; } return i; }
Union-Find Exercise: Percolation
Programming assignment Specification
My submission