For 2 minutes write down whatever comes to mind about the last class
This could be topics you learned
Questions you had
Connections you made
What is a Data Structure?
A data structure is defined by:
an organization of the data being stored
a set of operations for effective access to this data
Algorithmic complexity (efficiency) is directly tied to data organization
searching for an element in an unsorted array takes linear time: 232 = 4, 294, 967, 296
searching for an element in a sorted array takes logarithmic time: 32
Key to computing efficiency is reducing algorithmic complexity
Relation to Abstract Data Types
Abstract Data Type specifications are given in terms of:
an abstract data representation
a set of operations over the abstract representation
signature or interface
semantics
A data structure is a concrete realization of the ADT
it should preserve encapsulation
it can be analyzed with respect to performance
at the formal level - time and space complexity
at the execution level - runtime and resource usage
Common Data Structures
Some basic data structures are built into the language:
arrays
Some data structures are provided in standard libraries:
linked lists
hash tables
search trees
Other data structures need to be explicitly coded:
trees
graphs
Generic types facilitate generality and reuse
Java collections expand the range of ready to use common data structures
designed, coded, and optimized
Illustration: Linked List
Illustration: Defining a linked list in Java
public class LinkedList {
private Node first;
private Node last;
public LinkedList() {
last = first = null;
}
public void add(Object element) {
// add element to the end
}
public void remove() {
// remove element from the front
}
public Object getHead() {
// return the head of the list
}
public LinkedList getTail() {
// return the tail of the list
}
}
Illustration: Defining a Node
public class Node {
private Node next;
private Object element;
public Node(Object element, Node next) {
this.element = element;
this.next = next;
}
public Object getElement() { return element; }
public void setElement() {
this.element = element;
}
public Node getNext() { return next; }
public void setNext(Node next) {
this.next = next;
}
}
Generics to the rescue!
public class LinkedList<T> {
private Node<T> first;
private Node<T> last;
//...
public class Node<T> {
private Node<T> next;
private T element;
//...
}
Design Concerns: Memory Leaks
Memory leaks are serious programming errors-hard to debug
They happen when references are maintained to objects no longer in use
Cloning is a powerful, but controversial, feature in Java
Java provides two forms of cloning
shallow – a new object is created and the fields of the original are copied without change
Default strategy provided by Object.clone()
deep – a new object is created and cloning is applied recursively to each field
Must override clone() to implement this strategy
Great care needs to be exercised to apply it correctly
It is generally recommended to provide a copy constructor
Cloning vs Copy Constructor
Copy constructor is easier as we do not need to handle CloneNotSupportedException
clone method returns Object which we then need to cast
We cannot assign to final fields in clone method
Cloning vs Copy Constructor
public class BadClone
implements Cloneable {
private final int x;
public BadClone(int x) {
this.x = x;
}
// Omits throws for brevity
@Override
protected Object clone() {
BadClone badClone =
(BadClone) super.clone();
// Can't change x!
// badClone.x = 5;
return badClone;
}
}
public class GoodClone {
private final int x;
public GoodClone(int x) {
this.x = x;
}
// Copy constructor
public GoodClone(GoodClone other) {
// I can now set x!
this.x = other.x + 1;
}
}
Design Concerns: Encapsulation Cracks
The object creator retaining access:
exposes access to the data structure internals
introduces side effects that break the class contract
cloning/copying is one way to avoid this design flaw
Illustration: Creator Retaining Access
Design Concerns: Encapsulation Cracks
An internal object is returned to the caller
providing access to the data structure internals
enabling side effects that break the class contract
creating the potential to break the integrity of the data structure
Illustration: Returning Internal Object
Collections
Collections or containers:
allow programmers to hold and organize sets of objects
in useful and efficient ways
as part of consistent and flexible framework
Java provides us with many standard collection interfaces and implementations
Core Collection Interfaces
Collection – root of the collection hierarchy
Set – no duplicates
List – ordered collection, sequence
Queue – holds elements for processing
Deque – double ended queue
Map – maps keys to values
Collection Interface
size, isEmpty
contains
add, addAll
remove, removeAll, retainAll, clear
toArray
iterator (because Collection implements Iterable)
Optional methods that are not supported by a specific implementation throw UnsupportedOperationException
List
add, addAll – add to end of the list
remove – removes first occurrence
iterator, listIterator
indexOf, lastIndexOf – find index of element
get, set – access element at given index
subList – view portion of list as a List
Queue
Insert – add, offer
Remove – remove, poll
Examine – element, peek
Queues usually use FIFO order.
PriorityQueue will use natural ordering or a Comparator.
Map
Maps keys to values. Does not implement Collection itself, but has three collection views
keySet – Set of the keys
values – Collection of values
entrySet – Set of key-value mappings.
Beware of using mutable objects as keys!
put – associate a key with a value
get – get value associated with key
remove – remove key/value mapping
containsKey, containsValue
Bad Map
What would be so bad about having mutable keys?
Well once you change an element in the key which contributes to say the hashing function it won’t work in the map anymore!