Abstract Data Types An abstraction hides certain details at certain

Abstract
Data
Types
An
abstraction
hides
certain
details
at
certain
times.
A
data
abstraction
describes
WHAT
information
is
stored
in
an
object
without
being
specific
about
HOW
the
information
is
stored
or
organized.
The
methods
of
an
object
specify
WHAT
you
can
do
with
an
object
without
being
specific
HOW
it
is
achieved.
The
advantages
of
abstractions
is
that
a
designer
can
start
with
how
the
data
object
will
be
used,
and
postpone
implementation
decisions
in
a
piecemeal
manner,
postponing
until
later.
Clients
of
an
object
need
only
know
how
to
use
the
object
through
its
methods.
This
information
hiding
allows
the
designer
to
change
the
implementation
of
the
object
without
affecting
the
client.
The
combination
of
data
together
with
its
methods
is
called
an
Abstract
Data
Type
(ADT).
A
Java
Interface
is
a
way
to
specify
(but
not
implement)
an
ADT.
It
specifies
the
names,
parameters,
and
return
types
(ie,
header)
of
the
ADT
methods.
The
interface
does
not
specify
the
data
fields
(except
public
constants),
as
that
is
an
implementation
detail.
A
Java
Interface
specifies
the
requirements
of
an
ADT
as
a
contract
between
the
service
provider
(class
that
implements
the
ADT)
and
the
client
(the
user
of
the
class).
List
Interface
A
Java
Interface
specifies
the
methods
required
for
all
implementations
of
it.
It
tells
programmers
how
to
invoke
the
methods
of
any
class
that
implements
the
interface,
regardless
of
the
representation
of
the
data
or
how
the
methods
do
their
job.
The
Java
List
Interface
specifies
an
abstract
data
type
referred
to
as
an
ordered
collection:
• The
elements
of
a
collection
can
be
accessed
by
their
integer
index
(position
in
the
list)
starting
at
index
0.
• There
can
be
duplicate
elements
in
the
list
(unlike
Sets).
• Most
implementations
allow
nulls
in
the
list.
An
implementation
of
the
List
Interface
is
the
ArrayList
class.
Later
we
will
look
at
another
implementation
LinkedList
class.
The
MyList
Interface
is
a
subset
of
the
methods
specified
in
the
Java
List
interface.
It
includes
that
most
commonly
used
methods.
(Aside:
The
MyList
Interface
included
JavaDoc
comments,
which
are
specified
in
/** … */
comments
(distinct
from
/* … */ comments).
These
comments
include
special
tags,
such
as
@returns,
@param,
@throws.
The
Javadoc
tool
turns
these
Javadoc
comments
into
a
formatted
html
document
in
the
standard
Java
API
documentation
style.
In
Eclipse,
you
can
run
the
Javadoc
tool
from
the
Project
menu.)
MyArrayList
Now
let’s
look
at
the
MyArrayList
class.
It
is
an
implementation
of
the
MyList
interface.
This
class
uses
an
array
to
maintain
the
data.
First
consider
the
following
code
that
uses
a
MyArrayList.
object
MyArrayList<String> names = new MyArrayList<String>();
names.add("Tom");
names.add("Dave");
names.add("Jim");
String t = names.get(0);
names.set(0, "Thomas");
names.add("Guy");
names.remove(1);
names.add(0, “Margaret”);
What
is
a
constraint
with
an
array?
It
size
is
fixed.
Once
you
specify
the
size,
you
cannot
change
the
size.
But
if
you
don't
know
in
advanced
how
big
to
make
the
array,
what
can
you
do?
One
approach
is
to
make
the
array
bigger
than
the
biggest
expected
size
(and
hope
you
don't
need
a
bigger
size).
We
present
a
solution
that
gives
the
appearance
that
the
array
changes
size,
by
filling
the
array
starting
at
the
beginning
of
the
array
and
keeping
track
of
how
many
elements
are
in
the
array.
We
look
at
these
filled
entries
only.
If
we
remove
an
entry,
we
make
sure
that
the
beginning
of
the
array
stays
full,
by
shifting
the
elements
towards
the
beginning
of
the
array
to
fill
any
gap
created
by
the
removed
entry.
// Class invariant: All the elements of the list are
// at index 0,1,2,3,...,size-1 of the array.
public class MyArrayList<E> implements MyList<E> {
private final int INITIAL_CAPACITY;
private E[] values;
private int size;
public MyArrayList() {
INITIAL_CAPACITY = 10;
values = (E[]) new Object[INITIAL_CAPACITY];
size = 0;
}
The
MyArrayList
class
has
three
fields.
The
first
field
is
the
size
we
will
initially
create
the
array.
It
indicates
the
capacity
of
the
collection
(like
the
size
of
a
bag).
(Later
we
will
see
how
to
make
the
array
bigger
as
needed.)
The
next
two
fields
are
the
array
and
the
number
of
elements
in
the
“bag”.
We
sometimes
call
the
size
field
a
companion
variable,
because
the
array
values
needs
the
size
variable
to
know
how
many
elements
of
the
list
it
is
holding.
(What
does
final
mean?
It
is
a
constant)
Notice
that
the
Class
header
has
a
new
component
<E>.
The
<E>
is
the
type
parameter
that
specifies
the
type
of
the
elements
that
will
be
in
the
array
list.
When
a
MyArrayList
object
is
created
with
the
new
operator,
the
type
specified
is
the
value
of
the
type
parameter
<E>.
For
example,
MyArrayList names = new MyArrayList<String>();
specifies
that
<E>
should
have
the
value
String
for
the
names
array
list.
If
we
wrote,
MyArrayList ages = new MyArrayList<Integer>(); the
type
parameter
<E>
would
be
Integer
for
the
ages
array
list.
A
type
parameter
is
analogous
to
a
method
parameter,
which
can
get
different
values
every
time
the
method
is
called.
We
will
use
this
type
parameter
E
whenever
we
need
to
declare
an
object
that
has
the
same
type
as
the
elements
of
the
array.
Thus,
we
declare
the
array
values
to
have
type
E[].
In
the
constructor,
we
create
the
array
and
the
set
the
size
of
the
array
list
to
0,
since
there
are
no
elements
in
the
list
at
this
point.
Notice
how
the
array
is
created.
We
can
only
create
arrays
of
type
Object[].
(Every
object
in
Java
is
of
type
Object.)
But
because
values
is
declared
as
type
E[],
we
need
to
cast
the
new
array
to
be
type
(E[]).
(The
reason
that
the
array
must
be
created
as
type
Object[]
is
quite
subtle
and
won’t
be
explained
here.)
Finally,
notice
the
comment
about
the
class
invariant.
A
class
invariant
is
a
statement
about
the
public
methods
of
the
class.
If
the
statement
is
true
before
a
public
method
is
called,
then
the
method
must
ensure
that
when
execution
has
completed
the
statement
is
still
true.
If
every
public
method
maintains
the
invariant,
then
the
invariant
is
always
true
before
and
after
any
public
method
is
called.
A
class
invariant
is
both
a
precondition
and
a
postcondition
of
every
public
method.
public int size() {
return size;
}
// always returns true
public boolean add(E value) {
if (size == values.length)
expand();
values[size] = value;
size++;
return true;
}
The
size
method
(above)
does
not
change
the
list.
If
the
invariant
is
that
the
all
the
elements
are
at
the
beginning
of
the
list
as
a
contiguous
block
from
index
0
to
size
-1,
then
the
size
variable
is
the
number
of
elements
in
the
list.
On
the
other
hand
the
add
method
does
change
the
list.
It
adds
an
element
to
the
end
of
the
list.
It
can
only
add
the
element
if
there
is
enough
space
in
the
array.
If
the
array
is
full,
it
calls
the
expand
method
(that
“magically”
grows
the
array).
The
next
unused
space
in
the
array
is
at
index
size.
To
maintain
the
class
invariant,
the
size
field
must
also
be
incremented
to
match
the
number
elements
in
the
array.
Finally,
add
returns
true
to
indicate
that
the
element
was
added.
(Later,
we
will
see
that
the
add
version
of
the
Set
abstract
data
type
will
not
add
an
element
if
it
is
already
in
the
set.)
public E get(int index) {
if (index < 0 || index >= size)
throw new ArrayIndexOutOfBoundsException(index);
return values[index];
}
//returns the value that used be at index
public E set(int index, E value) {
if (index < 0 || index >= size)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = values[index];
values[index] = value;
return oldValue;
}
The
set
and
get
methods
simply
get
and
set
the
element
at
the
index
specified.
That
index
is
out
of
bounds
if
no
element
is
at
that
index.
Notice
that
it
can
be
out
of
bounds,
even
if
it
is
not
out
of
the
bounds
of
the
array.
Also
notice
that
the
set
method
returns
the
element
at
the
specified
index
prior
to
being
overwritten
with
the
new
element.
There
are
times
that
getting
the
old
value
can
be
handy
when
using
lists
and
it
costs
little
to
provide
that
capability.
public E remove(int index) {
if (index < 0 || index >= size)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = get(index);
for (int hole = index; hole < size - 1; hole++)
values[hole] = values[hole + 1];
values[size - 1] = null;
size--;
return oldValue;
}
The
remove
method
removes
the
element
at
the
specified
index
and
returns
it.
To
maintain
the
class
invariant,
the
elements
after
the
removed
element
must
be
shifted
towards
the
front
of
the
array
to
fill
the
hole
created
by
the
removed
element,
and
the
size
needs
to
be
decremented.
The
shift
requires
copying
each
element
forward
one
element.
Notice
that
only
elements
up
to
size
are
shifted,
as
any
element
after
that
is
not
part
of
the
list.
When
shifting
elements,
it
is
useful
to
draw
a
picture
of
a
small
array
that
is
not
completely
full.
Then
consider
how
the
elements
need
to
be
shifted.
Create
a
table
that
shows
the
how
the
elements
will
be
copied.
Which
should
be
the
first
copied?
Which
should
be
the
last
copied?
The
loop
can
either
loop
over
the
indices
in
the
To
column
or
the
From
column.
Then
the
assignment
must
reflect
your
choice.
In
the
code
above
the
hole
variable
is
the
same
as
To.
Inserting
an
element
at
a
specified
index
was
left
as
an
exercise.
Notice
that
an
index
is
not
out
of
bounds
if
it
is
the
index
immediately
after
the
last
element,
as
you
may
add
an
element
at
the
end
of
the
list.
public void add(int index, E value) {
if (index < 0 || index > size)
throw new ArrayIndexOutOfBoundsException(index);
if (values.length == size)
expand();
for (int i = size - 1; i >= index; i--)
values[i + 1] = values[i];
values[index] = value;
size++;
}
Runtimes
size()
get(int)
set(int, E)
add(E)
add(int, E)
remove(int)
O(1)
O(1)
O(1)
O(1)
(ignoring
cost
for
expand)
O(n)
Worst‐case
O(n)
Average‐case
O(1)
Best
case
(ignoring
cost
for
expand)
O(n)
Worst‐case
O(n)
Average‐case
O(1)
Best
case