0% found this document useful (0 votes)
12 views

CSCI1933 Lecture9

Uploaded by

Michael Zhang
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views

CSCI1933 Lecture9

Uploaded by

Michael Zhang
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 119

Csci 1933: Introduction to

Algorithms and Data Structures


Spring 2022
Announcements

• Project 3 due 3/30, 11:55pm

• Lab 8 milestones due tomorrow (3/25)

• Midterm 2 in 2 weeks!
Midterm 2
• Thursday, April 7, 6:30-8:30pm
• Closed book, closed computer
• You are allowed 1 page (8.5” x 11”)
(2 sides) of handwritten notes

• Time limit: 2 hrs

• Example midterm + list of topics is posted


on Canvas
Project #3 clarifications

• we had a typo in Project #3 doc– our data is for a 1000x1000


matrix, not an 800x800 matrix—see updated doc
• MatrixEntry should be a separate class (not a private inner
class) (remember you’ll just need to use its public interface to
access nextColumn, nextRow)
• Don’t turn a sparse matrix into a complete matrix with zeros
(the whole point is storage efficiency); If an entry is zero,
don’t store it in the sparse matrix (e.g. careful with plus and
minus methods! )
• assume zero-based indexing for the rows/columns– element
in first row/first column is (0,0); your code should discard any
input data that’s out-of-range
Overview of today’s material
- Lists
- Finish linked list implementation
- Comparison of array-based list
implementation to linked list implementation

- “Exceptions” in Java
- Iterators

- Start on new ADT: Stacks


Brief review of key concepts covered last time
Abstract data types and data
structures
Abstract Data Type: definition

• A list is an example of an abstract data type (ADT)

• What is an ADT?: a set of operations that can be performed,


along with rules for how the class behaves under those
operations
NOT: an implementation, not even a type of storage
(not even language-specific, “abstract”)

Data structure: specific implementation of an ADT (e.g. in Java)


Specifications for the List ADT
• Data:
– a collection of objects in a specific order, having the
same type
– the number of objects in the collection
• Operations
– Add new entry – at end, or anywhere
– Remove an item
– Remove all items
– Replace an entry
– Look at any entry
– Look for an entry of a specific value
– Count how many entries
– Check if list is empty, full
See ListInterface.java
– Display all the entries
Carrano and Henry, Data Structures and Abstractions with Java.
Start of an Array List implementation

/**
A class that implements a list of objects by using an array.
Entries in a list have positions that begin with 1.
Duplicate entries are allowed. */

public class AList<T> implements ListInterface<T>


{
private T[] list; // Array of list entries; ignore list[0]
private int numberOfEntries;

private static final int DEFAULT_CAPACITY = 25;


private static final int MAX_CAPACITY = 10000;

public AList()
{
this(DEFAULT_CAPACITY);
} // end default constructor
Implementing add method
Task: Adds newEntry to the end of the list.
Input: newEntry is an object.
Output: None.

public void add(T newEntry)


{

if(numberOfEntries == list.length) {
// Error--list full!! Report or handle here
}
else {
list[numberOfEntries + 1] = newEntry;
numberOfEntries++;

}
} // end add
Implementing second add method

public void add(int givenPosition, T newEntry)


{

if ((givenPosition >= 1) && (givenPosition <= numberOfEntries + 1))


{
if (givenPosition <= numberOfEntries)
makeRoom(givenPosition);
list[givenPosition] = newEntry;
numberOfEntries++;
}

else System.out.println(“Index out of bounds!”);


//or throw new IndexOutOfBoundsException("Given position of add's new entry is out of bounds.");

} // end add

Carrano and Henry, Data Structures and Abstractions with Java.


How about the remove method?
public T remove(int givenPosition)

Task: Removes and returns the entry at position givenPosition.


Input: givenPosition is an integer.
Output: Either returns the removed entry or throws an exception if
givenPosition is invalid for this list. Note that any value of givenPosition is
invalid if the list is empty before the operation.

mylist.remove(2)

Note: we
need the
opposite of
“makeRoom”
method
here
removeGap
Carrano and Henry, Data Structures and Abstractions with Java.
remove method implementation
public T remove(int givenPosition)
{
checkIntegrity();
if ((givenPosition >= 1) && (givenPosition <= numberOfEntries))
{

T result = list[givenPosition]; // Get entry to be removed

// Move subsequent entries towards entry to be removed,


// unless it is last in list
if (givenPosition < numberOfEntries)
removeGap(givenPosition);
list[numberOfEntries] = null;
numberOfEntries--;
return result; // Return reference to removed entry
}
else
throw new IndexOutOfBoundsException("Illegal position given to
remove operation.");
} // end remove
Addressing the fixed array length
limitation– ensureCapacity method

private void ensureCapacity()


{
int capacity = list.length - 1;
if (numberOfEntries >= capacity)
{
int newCapacity = 2 * capacity;
list = Arrays.copyOf(list, newCapacity + 1);
} // end if
}
Updated add methods for dynamic
array implementation
public void add(T newEntry)
{
list[numberOfEntries + 1] = newEntry;
numberOfEntries++;
ensureCapacity();
} // end add

public void add(int givenPosition, T newEntry)


{

if ((givenPosition >= 1) && (givenPosition <= numberOfEntries + 1))


{
if (givenPosition <= numberOfEntries)
makeRoom(givenPosition);
list[givenPosition] = newEntry;
numberOfEntries++;
ensureCapacity(); // Ensure enough room for next add
}
else
throw new IndexOutOfBoundsException(
"Given position of add's new entry is out of bounds.");
} // end add
Review: array-based List implementation
Think in terms of: computational efficiency, storage efficiency,
ease of implementation
• Advantages?
• Retrieving an entry is fast
• Adding an entry at the end of the list is fast
• Arrays are a natural way of thinking about lists of elements
(easy to program?)
• Disadvantages?
• Adding or removing an entry that is between other
entries requires shifting elements in the array (potentially
slow)
• Increasing the size of the array or vector requires
copying elements (potentially slow)
Linked lists
An alternative list implementation: the linked list

Array: fixed size, each position is directly addressable

Linked list:
• List is organized by keeping track of start (or end) only
• Each element of the list knows about the next element in the list
Linked list (LList) implementation
• Now that we understand the logic, let’s think about how we’d
implement a “linked list”
• Steps:
– what type of structure (e.g. array) should we use to store
data elements (objects) in the list?
– how do we implement the standard list methods
• NOTE: we need all of the same methods that we used
for the array-based list, we’re just changing how they
interact with the data stored in this list
public class LList < T > implements ListInterface < T > {

//what goes here?

}
What type of structure/variable will we
need to store elements of a linked list?
• Requirements?
• should keep track of our data!
(e.g. patient info, illness, etc.)
• needs to store a reference to
the next patient
The Node inner class
public class LList < T > implements ListInterface < T > {
private class Node
{
private T data; // entry in list
private Node next; // link to next node
private Node(T dataPortion)
{
data = dataPortion;
next = null;
} // end constructor
private Node(T dataPortion, Node nextNode)
{
data = dataPortion;
next = nextNode;
} // end constructor data next
} // end Node

// other class definition code here


} //end LList
How do we use this inner class?
public class LList<T> implements ListInterface<T>
{
private Node firstNode; // reference to first node
private int length; // number of entries in list

public LList()
{
clear();
} // end default constructor

public final void clear()


{
firstNode = null;
length = 0;
} // end clear

//rest of the definition here (including Node inner class)


}
How do we implement the linked list
methods?
• Remember, implementing the ListInterface requires
that we implement all core list functionality:
• add(T)
• add(i, T)
• remove(i)
• replace(i,T)
• getEntry(i)
• contains(T)
• clear(), getLength(), isEmpty(),
isFull()
Adding elements to a linked list
• Now, how about the linked list?

public void add(T newEntry){

First, let’s start by thinking of the possible starting states for the
list...
Adding elements to a linked list

• Possible cases:
– adding element to an empty list
– adding element to a list with existing
elements
Adding to the End of the List
(empty case)

(a) An empty list and a new node;


(b) after adding a new node to a list that was empty
Carrano and Henry, Data Structures and Abstractions with Java.
Adding elements to a linked list
public boolean add(T newEntry)
{
Node newNode = new Node(newEntry);

if (isEmpty()) {

} else // add to end of nonempty list


{
Node lastNode = getNodeAt(length);

// make last node reference new node


lastNode.next = newNode;

} // end if

length++;
return true;
} // end add
Adding elements to a linked list
public boolean add(T newEntry)
{
Node newNode = new Node(newEntry);

if (isEmpty())
firstNode = newNode;
else // add to end of nonempty list
{
Node lastNode = getNodeAt(length);

// make last node reference new node


lastNode.next = newNode;

} // end if

length++;
return true;
} // end add
Adding to the End of the List (non-
empty case)

A chain of nodes (a) just prior to adding a node at the end;


(b) just after adding a node at the end.
Adding elements to a linked list
public boolean add(T newEntry)
{
Node newNode = new Node(newEntry);

if (isEmpty())
firstNode = newNode;
else // add to end of nonempty list
{
Node lastNode = getNodeAt(length);

// make last node reference new node


lastNode.next = newNode;

} // end if

length++;
return true;
} // end add
New material
Overview of today’s material

- Lists
- Finish linked list implementation
- Comparison of array-based list
implementation to linked list implementation

- “Exceptions” in Java
- Iterators

- Start on new ADT: Stacks


Exercise: We used a helper function getNodeAt
– how do we implement this?
public class LList<T> implements ListInterface<T>
{
private Node firstNode; // reference to first node
private int length; // number of entries in list

private Node getNodeAt(int givenPosition) {

?
}

}
Exercise: We used a helper function getNodeAt
– how do we implement this?
public class LList<T> implements ListInterface<T>
{
private Node firstNode; // reference to first node
private int length; // number of entries in list

private Node getNodeAt(int givenPosition) {


Node currentNode = null;
if(!isEmpty() && (givenPosition >= 1) && (givenPosition <=
length) ) {

currentNode=firstNode;
for(int counter=1; counter < givenPosition; counter++) {
currentNode = currentNode.next;
}

}
return currentNode;
}

}
Now, how about adding elements in
the middle of a linked list?
public boolean add(int newPosition, T newEntry)

Let’s think about the possible cases:


• at the beginning of a list
• between two existing elements
• at the end of a list

Error conditions?
Case 1: adding at Beginning of the List

A chain of nodes (a) prior to adding a node at the beginning;


(b) after adding a node at the beginning.
Case 2: adding elements in the middle
of a linked list?

A chain of nodes (a) prior to adding node between


adjacent nodes; (b) after adding node between
adjacent nodes
public boolean add(int newPosition, T newEntry)
{
boolean isSuccessful = true;
if ((newPosition >=Valid
1) index
&& (newPosition
condition ? <= length+1))
{
Node newNode = new Node(newEntry);
if (isEmpty() || 1(newPosition
Case condition ? == 1)) // case 1
{
newNode.next = firstNode;
Case 1 code ?
firstNode = newNode;
}
else
{
Node nodeBefore = getNodeAt(newPosition - 1);
Node nodeAfter =Case
nodeBefore.next;
2/3 code ?
newNode.next = nodeAfter;
nodeBefore.next = newNode;
} // end if
length++;
}
else
isSuccessful = false;
return isSuccessful;
} // end add
Exercise
public boolean add(int newPosition, T newEntry)
{
boolean isSuccessful = true;
if ((newPosition >= 1) && (newPosition <= length+1))
{
Node newNode = new Node(newEntry);
if (isEmpty() || (newPosition == 1)) // case 1
{
newNode.next = firstNode;
firstNode = newNode;
}
else
{
Node nodeBefore = getNodeAt(newPosition - 1);
Node nodeAfter = nodeBefore.next;
newNode.next = nodeAfter;
nodeBefore.next = newNode;
} // end if
length++;
}
else
isSuccessful = false;
return isSuccessful;
} // end add
Other methods in LList

• add(T)
• add(i, T)
• clear(), getLength(), isEmpty()
• remove(i)
• replace(i,T)
• getEntry(i)
• contains(T)
Removing an element from a linked list
public T remove(int givenPosition)

• Should remove the element at the given position,


update links, etc.

• First, let’s think about the possible cases


Removing an element from a linked list
public T remove(int givenPosition)

• Should remove the element at the given position,


update links, etc.

• First, let’s think about the possible cases


1. Remove from beginning of the list
2. Remove from middle of the list
3. Remove from the end of the list
Case 1: removing an element at the
beginning

A chain of nodes (a) prior to removing first node;


(b) after removing the first node
Case 2,3: removing elements in the
middle/at the end

A chain of nodes (a) prior to removing interior node;


(b) after removing interior node
public T remove(int givenPosition)
{
T result = null; // return value
if ((givenPosition >= 1)index
Valid && (givenPosition
condition ? <= length))
{
if (givenPosition
Case 1 condition==? 1) {
result = firstNode.data;
Case 1 code ?
firstNode = firstNode.next;
}
else
{
Node nodeBefore = getNodeAt(givenPosition - 1);
Node nodeToRemove = nodeBefore.next;
Node nodeAfter = Case 2,3 code ?
nodeToRemove.next;
nodeBefore.next = nodeAfter;
result = nodeToRemove.data;
} // end if
length--;
} // end if
return result; // return removed entry, or
// null if operation fails
} // end remove
public T remove(int givenPosition)
{
T result = null; // return value
if ((givenPosition >= 1) && (givenPosition <= length))
{
if (givenPosition == 1) {
result = firstNode.data;
firstNode = firstNode.next;
}
else
{
Node nodeBefore = getNodeAt(givenPosition - 1);
Node nodeToRemove = nodeBefore.next;
Case 2 code ?
Node nodeAfter = nodeToRemove.next;
nodeBefore.next = nodeAfter;
result = nodeToRemove.data;
} // end if
length--;
} // end if
return result; // return removed entry, or
// null if operation fails
} // end remove
public T remove(int givenPosition)
{
T result = null; // return value
if ((givenPosition >= 1) && (givenPosition <= length))
{
if (givenPosition == 1) {
result = firstNode.data;
firstNode = firstNode.next;
}
else
{
Node nodeBefore = getNodeAt(givenPosition - 1);
Node nodeToRemove = nodeBefore.next;
Node nodeAfter = nodeToRemove.next;
nodeBefore.next = nodeAfter;
result = nodeToRemove.data;
} // end if
length--;
} // end if
return result; // return removed entry, or
// null if operation fails
} // end remove
Other methods in LList
• add(T)
• add(i, T)
• clear(), getLength(), isEmpty()
• remove(i)
• replace(i,T)
• getEntry(i) Exercise: Complete
these on your own
• contains(T)

– We don’t have time to cover all of these in detail, but


you should be able to implement them either for an
array-based list or a linked-list data structure

(see Carrano and Henry, Chapter 12, for details on linked list implementation)
Overview of today’s material

- Lists
- Finish linked list implementation
- Comparison of array-based list
implementation to linked list implementation

- “Exceptions” in Java
- Iterators

- Start on new ADT: Stacks


Comparison of array and linked list List
implementations

• Which is better?
– Space complexity?

– Time complexity?
Comparison of array and linked list List
implementations

• Which is better?
– Space?
• Array List: wastes memory for each unfilled
slot in the array
• Linked List: only create one node per element,
BUT requires memory overhead of links
Comparison of array and linked list List
implementations
• Which is better?
Assume N elements– what’s the number of operations in the worst case?

– Time complexity?
• getEntry (int position)
• Array List: ?
• Linked List: ?

Exercise: what is the worst-case time


complexity?
Comparison of array and linked list List
implementations
• Which is better?
Assume N elements– what’s the number of operations in the worst case?

– Time complexity?
• getEntry (int position)
• Array List: O(1) (doesn’t depend on the size of the
array)
• Linked List: requires traversal of all preceding elements
(worst-case: last element, complexity ~ O(N))
Comparison of array and linked list List
implementations
• Which is better?
Assume N elements– what’s the number of operations in the worst case?

– Time complexity?
• remove(int position)
• Array List: ?
• Linked List: ?

Exercise: what is the worst-case time


complexity?
Comparison of array and linked list List
implementations
• Which is better?
Assume N elements– what’s the number of operations in the worst case?

– Speed?
• remove(int position)
• Array List: needs reshuffling (worst case: first
element, complexity ~ O(N))
• Linked List: simply “rewire” links in constant time,
but we still need to find this element (worst case:
last element, complexity ~O(N))
Summary of Pros and Cons of a linked list
implementation
• The linked list can grow as large as necessary
• Can add and remove nodes without shifting existing
entries
But …
• Must traverse a chain to determine where to make
addition/deletion
• Retrieving an entry requires traversal
– As opposed to direct access in an array
• Requires more memory for links
– But does not waste memory for oversized array
Variations on the linked list
• Also include a tail reference (reference to the
last node of the list) Why?

• A doubly-linked list: each element knows


about both its left and right neighbor. Why?

• Multiply linked list (Project #3)


Tail Reference
Updated LList data member– lastNode

public class LList<T> implements ListInterface<T>


{
private Node firstNode; // reference to first node
private Node lastNode; // reference to last node
private int length; // number of entries in list

...

}
Adding elements to a linked list
public boolean add(T newEntry)
{
Node newNode = new Node(newEntry);

if (isEmpty())
firstNode = newNode;
else // add to end of nonempty list
{
Node lastNode = getNodeAt(length);

// make last node reference new node


lastNode.next = newNode;

} // end if

length++; Exercise: update the code in


return true; the box to use tail reference
} // end add
Adding elements to a linked list
public boolean add(T newEntry)
{
Node newNode = new Node(newEntry);

if (isEmpty())
firstNode = newNode;
else // add to end of nonempty list
{

lastNode.next = newNode;
lastNode = newNode;

} // end if

length++;
return true;
} // end add
Java Class Library: The Class LinkedList

• The standard java package java.util


contains the class LinkedList
• This class implements the interface List
• Contains additional methods
Overview of today’s material

- Lists
- Finish linked list implementation
- Comparison of array-based list
implementation to linked list implementation

- “Exceptions” in Java
- Iterators

- Start on new ADT: Stacks


Exceptions in Java
Exceptions

• An exception is an object that is created as a


signal that an unexpected event (error) has
occurred during execution
(e.g. array index out of bounds exception, file not
found exception, …)

• Two actions:
– Create “throw” an exception
– Handle exceptions
Exception example
public class FileReader {
public FileReader() {
}

public String readSequenceFromFile(String filename) {


//Getting input from a text file
String result = "";
try {
File f = new File(filename);
Scanner fileInput = new Scanner(f);

while (fileInput.hasNext()) {
result = result + fileInput.nextLine();
}
} catch(FileNotFoundException e) {
System.out.println("Sorry, can't find file!");
System.out.println(e.getMessage());
System.exit(1);
}

return result;
}
}

Main:
FileReader seqFile = new FileReader();

String sequence = seqFile.readSequenceFromFile(“yeast_chr16_genomesequence.txt");


System.out.println(sequence);
Try-catch blocks
try {
<some code that might throw an exception>
}
catch(Exception e) {
<code for handling the exception– only executed if
exception occurs>
}

Our example:
try {
File f = new File(filename);
Scanner fileInput = new Scanner(f);

while (fileInput.hasNext()) {
result = result + fileInput.nextLine();
}
} catch(FileNotFoundException e) {
System.out.println("Sorry, can't find file!");
System.out.println(e.getMessage());
System.exit(1);
}
What happens if we don’t use try-catch?
public String readSequenceFromFile(String filename) {
//Getting input from a text file
String result = "";
File f = new File(filename);
Scanner fileInput = new Scanner(f);

while (fileInput.hasNext()) {
result = result + fileInput.nextLine();
}

return result;
}

Not allowed! Java won’t compile because the Scanner constructor is


declared to throw an exception that must be handled
Another option: pass the exception
upward
public String readSequenceFromFileVer2(String filename)
throws FileNotFoundException {
//Getting input from a text file
String result = "";
File f = new File(filename);
Scanner fileInput = new Scanner(f);

while (fileInput.hasNext()) {
result = result + fileInput.nextLine();
}

return result;
}
Another option: pass the exception upward
public String readSequenceFromFileVer2(String filename)
throws FileNotFoundException {
//Getting input from a text file
String result = "";
File f = new File(filename);
Scanner fileInput = new Scanner(f);

while (fileInput.hasNext()) {
result = result + fileInput.nextLine();
}

return result;
}

Now main needs to look like this:


try {
sequence =
seqFile.readSequenceFromFileVer2(“yeast_chr16_genomesequence.txt");
System.out.println(sequence);
} catch(FileNotFoundException e) {
System.out.println("Sorry, can't find file!");
System.out.println(e.getMessage());
System.exit(1);
}

The exception must be caught at some point!


Checked vs. unchecked Exceptions

• Checked exceptions: must be handled (try-catch) or method declared as “throws”


• error condition that may get triggered due to system error (beyond the
programmers' control)

• Unchecked exceptions
• relates to error conditions that are triggered by badly written code (i.e. are the
programmer’s fault). Compiler doesn’t enforce handling of these

Slide adapted from: https://cis.gvsu.edu/~dulimarh/CS163/Lectures/Exceptions.html


Overview of today’s material
- Lists
- Finish linked list implementation
- Comparison of array-based list
implementation to linked list implementation

- “Exceptions” in Java
- Iterators

- Start on new ADT: Stacks


Iterators
Motivation
• We often want to access every item in a
data structure or collection in turn
– We call this traversing or iterating over or
stepping through or visiting every item in the
data structure or collection

• Example with an array:


for (int i = 0; i < arr.length(); i++)
/* do something to arr[i] */

(slide modified from James Hughes/Roberto Solis-Oba)


Motivation
• What if we want to traverse a collection of
objects? (e.g. list)
– Its underlying implementation may not be known
to us
• Java provides a common scheme for stepping
through all elements in any collection, called
an iterator

(slide modified from James Hughes/Roberto Solis-Oba)


What is an Iterator?
• An iterator is a mechanism used to step
through the elements of a collection one by
one
– Each element is “delivered ” exactly once
• Example
– Iterate through an ordered list and print each
element in turn

5 9 23 34

(slide modified from James Hughes/Roberto Solis-Oba)


What is an Iterator?
• An iterator is a mechanism used to step
through the elements of a collection one by
one
– Each element is “delivered ” exactly once
• Example
– Iterate through an ordered list and print each
element in turn

5 9 23 34

(slide modified from James Hughes/Roberto Solis-Oba)


What is an Iterator?
• An iterator is a mechanism used to step
through the elements of a collection one by
one
– Each element is “delivered ” exactly once
• Example
– Iterate through an ordered list and print each
element in turn

5 9 23 34

(slide modified from James Hughes/Roberto Solis-Oba)


What is an Iterator?
• An iterator is a mechanism used to step
through the elements of a collection one by
one
– Each element is “delivered ” exactly once
• Example
– Iterate through an ordered list and print each
element in turn

5 9 23 34

(slide modified from James Hughes/Roberto Solis-Oba)


Iterator interface
• An Iterator is an object that enables you to traverse
through a collection and to remove elements from the
collection selectively, if desired. You get an Iterator for a
collection by calling its iterator() method. The following
is the Iterator interface.

public interface Iterator<E> {


boolean hasNext();
E next();
void remove(); //optional
}

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Iterator.html
How would we use an iterator?
//for an already defined List called “list”

Iterator<String> it = list.iterator();
while( it.hasNext() ) {
String temp = it.next();
System.out.println( temp );
}

Note: An iterator object is a “one shot” object-- it is designed to


go through all the elements of a collection and if you want to
repeat, you get another iterator object
How would we implement an iterator?
• Could be implemented in a separate class,
pass a referece to the data structure on which
we want to iterate

• Could be implemented in an inner class

• Could be implemented as part of the ADT


itself (e.g. add methods that provide this
functionality)
How would we implement an iterator?
• Could be implemented in a separate class,
pass a referece to the data structure on which
we want to iterate See Textbook Ch. 13
for an example of this

• Could be implemented in an inner class

• Could be implemented as part of the ADT


itself (e.g. add methods that provide this
functionality)
Array-Based Implementation
/** A class that implements the ADT list by using a resizable array and
gives it an iterator. */
public class ArrayListWithIterator<T> implements ListWithIteratorInterface<T>
{
private T[] list; // Array of list entries; ignore list[0]
private int numberOfEntries;
private boolean integrityOK = false;
private static final int DEFAULT_CAPACITY = 25;
private static final int MAX_CAPACITY = 10000;

public ArrayListWithIterator()
{
this(DEFAULT_CAPACITY);
} // end default constructor

Carrano and Henry, Data Structures and Abstractions with Java.


Array-Based Implementation

….
Provide method to
public Iterator<T> iterator()
create iterator
{
return new IteratorForArrayList();
} // end iterator

public Iterator<T> getIterator()


{
return iterator();
} // end getIterator

….

Carrano and Henry, Data Structures and Abstractions with Java.


Array-Based Implementation
(inner class)
private class IteratorForArrayList implements Iterator<T>
{
private int nextIndex; // Index of next entry in the iteration
private boolean wasNextCalled; // Needed by remove

private IteratorForArrayList()
{
nextIndex = 1; // Iteration begins at list's first entry
wasNextCalled = false;
} // end default constructor

// Implementations of the methods in the interface Iterator go here.

} // end IteratorForArrayList
} // end ArrayListWithIterator

Carrano and Henry, Data Structures and Abstractions with Java.


Exercise: hasNext() implementation for ArrayList
/** A class that implements the ADT list by using a resizable array and
gives it an iterator. */
public class ArrayListWithIterator<T> implements ListWithIteratorInterface<T>
{
private T[] list; // Array of list entries; ignore list[0]
private int numberOfEntries;

private class IteratorForArrayList implements Iterator<T>


{
private int nextIndex; // Index of next entry in the iteration
private boolean wasNextCalled; // Needed by remove

private IteratorForArrayList()
{
nextIndex = 1; // Iteration begins at list's first entry
wasNextCalled = false;
} // end default constructor

// Implementations of the methods in the interface Iterator go here.

} // end IteratorForArrayList
} // end ArrayListWithIterator

Method hasNext
Carrano and Henry, Data Structures and Abstractions with Java.
Array-Based Implementation

public boolean hasNext()


{
return nextIndex <= numberOfEntries;
} // end hasNext

Method hasNext
Carrano and Henry, Data Structures and Abstractions with Java.
Array-Based Implementation
public T next()
{
checkIntegrity();
if (hasNext())
{
wasNextCalled = true;
T nextEntry = list[nextIndex];
nextIndex++; // Advance iterator
return nextEntry;
}
else
throw new NoSuchElementException("Illegal call to next(); " +
"iterator is after end of list.");
} // end next

Method next

Carrano and Henry, Data Structures and Abstractions with Java.


Array-Based Implementation

The array of list entries and nextIndex (a) just before the call to
next; (b) just after the call to next but before the call to remove;
(c) after the call to remove
Carrano and Henry, Data Structures and Abstractions with Java.
Array-Based Implementation
public void remove()
{
checkIntegrity();
if (wasNextCalled)
{
// nextIndex was incremented by the call to next, so it is
// 1 larger than the position number of the entry to be removed
ArrayListWithIterator.this.remove(nextIndex − 1);
nextIndex−−; // Index of next entry in iteration
wasNextCalled = false; // Reset flag
}
else
throw new IllegalStateException("Illegal call to remove(); " +
"next() was not called.");
} // end remove

The method remove.

Carrano and Henry, Data Structures and Abstractions with Java.


The Iterable Interface
• Related to iterator interface

• One required method in the interface:


public Iterator<T> iterator()

• Anything that implements the Iterable interface can be


used in the for each loop, e.g.

ArrayList<Integer> list;
//code to create and fill list here
int total = 0;
for( int x : list )
total += x;
Java Collection interface
(extends the Iterable
interface)

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Collection.html
Iterator summary
• Iterators provide a convenient interface for
traversing through elements of a given data
structure
• Inner class implementations can usually be made
more efficient
• Many built-in Java data structures provide
iterators (all classes that implement Collection
interface)

Lab 9: you will implement inner class iterator for


linked list
What you should know about
iterators

• What iterators are/why they’re useful


• How to use them for built-in Java classes
(Collections)
• How to implement them for data structures
we discuss
Overview of today’s material
- Lists
- Finish linked list implementation
- Comparison of array-based list
implementation to linked list implementation

- “Exceptions” in Java
- Iterators

- Start on new ADT: Stacks


More Abstract Data Types:
• Stacks

• Queues (deques, priority queues)

Later:
• Dictionaries (hashes)
• Graphs
• Trees
A Stack abstract data type
• Organizes entries according to order in which added
• Additions are made to one end (the top)
• The item most recently added is always on the top
• Items can only be removed from the top

Carrano and Henry, Data Structures and Abstractions with Java.


Behavior of a Stack ADT
• Last in, first out (LIFO)
(not first-in, first-out)

• Note: cannot access elements that aren’t at the top


• Like a packed elevator loading/unloading
“pop”
“push”
“pop”
“push”
“push”
“push”

Carrano and Henry, Data Structures and Abstractions with Java.


A real-world CS example of stacks: the
Program (or Run-time) Stack
• Program counter references the current instruction
• When a method is called:
• Runtime environment creates activation record (also
called frame)
• Shows method's state during execution (stores local
variables, input parameters, return address to the
method’s caller)
• Each frame is pushed onto the program stack
• Top of stack belongs to currently executing method
• Next method down is the one that called current method

Carrano and Henry, Data Structures and Abstractions with Java.


The Program Stack

The program stack at 3 points in time; (a) when main begins execution; (b)
when methodA begins execution, (c) when methodB begins execution.

Carrano and Henry, Data Structures and Abstractions with Java.


What happens to the program
stack during recursion?
public double factorial(int x) {
double result;
if(x == 1) { result=1;}
else {
result = x*factorial(x-1);
}
return result;
}

In Main:

int result;
result = factorial(4);

Some of you may have noticed that recursive programs


sometimes result in memory errors– this is why!
Stack specifications
• Data:
– Collection of objects in reverse chronological
order, all having the same type
• Operations:
push(newEntry) Pushes newEntry onto top of stack
pop() Removes element from the top and returns it
peek() Returns element at the top (doesn’t modify stack)
isEmpty() Checks if stack is empty
clear() Clears the stack
Exercise #1: reversing a string

• Write code that uses a stack to reverse a string


– Operations: push, pop, isEmpty
public static String reverseString(String str) {
Stack<Character> st = new Stack<Character>();

char[] chars = str.toCharArray();


String rev = "";

for(char c:chars) {
st.push(c);
}

while(!st.isEmpty()) { rev += st.pop(); }


return rev;
}
Exercise: checking an expression for proper use
of brackets/parentheses

• Write pseudocode that uses a stack to check a string


(e.g. Java code) for proper use of brackets ( any of (, [,
{ )
– Brackets must be properly matched with each
other (-) {-} [-]
– Brackets must be balanced (i.e. no open blocks)
Example inputs:
while(n > 0) { while(n > 0) {
myStack.push(n); myStack.push(n;
n--; n--;
} }
Pseudocode for bracket checker

Create an empty stack

Traverse the string with the expression to be checked


- If the current character is a starting bracket (‘(‘ or ‘{‘ or ‘[‘),
then push it to stack.

- If the current character is a closing bracket (‘)’ or ‘}’ or ‘]’),


then pop from stack, check if the current char matches what was
popped, if they don’t matcherror!

After complete traversal, if there are any starting brackets left in the stack– not
balanced
Check our solution on our example
Create an empty stack

Traverse the string with the expression to be checked


- If the current character is a starting bracket (‘(‘ or ‘{‘ or ‘[‘),
then push it to stack.

- If the current character is a closing bracket (‘)’ or ‘}’ or ‘]’),


then pop from stack, check if the current char matches what was popped, if they don’t
matcherror!

After complete traversal, if there are any starting brackets left in the stack– not balanced

while(n > 0) { while(n > 0) {


myStack.push(n); myStack.push(n;
n--; n--;
} }
Formalizing Stack ADT specs
public interface StackInterface<T>
{
/** Task: Adds a new entry to the top of the stack.
* @param newEntry an object to be added to the stack */
public void push(T newEntry);

/** Task: Removes and returns the stackÕs top entry.


* @return either the object at the top of the stack or, if the
* stack is empty before the operation, null */
public T pop();

/** Task: Retrieves the stack’s top entry.


* @return either the object at the top of the stack or null if
* the stack is empty */
public T peek();

/** Task: Detects whether the stack is empty.


* @return true if the stack is empty */
public boolean isEmpty();

/** Task: Removes all entries from the stack */


public void clear();
} // end StackInterface
Now, let’s think about a Stack
implementation
Note: we’ve already experimented with the ADT before even talking
about how it was implemented

push(newEntry) Let’s try:


pop()
peek() • linked lists
isEmpty() • arrays
clear()
Stack implementation
• Let’s sketch a solution using:
• Linked lists
• Arrays
• No code yet– just rough idea of structure
A Linked Stack implementation
When using a chain of linked nodes to
implement a stack
The first node should reference the stack's top

Carrano and Henry, Data Structures and Abstractions with Java.


An Array-Based Stack Implementation

An array that implements a stack; its first location references


the bottom of the stack

Carrano and Henry, Data Structures and Abstractions with Java.

You might also like