0% found this document useful (0 votes)
16 views115 pages

CSCI1933 Lecture8

Uploaded by

Michael Zhang
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views115 pages

CSCI1933 Lecture8

Uploaded by

Michael Zhang
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 115

Csci 1933: Introduction to

Algorithms and Data Structures


Spring 2022
Announcements

• Project 3 assigned, due 3/30

• Lab 7 milestones due tomorrow (3/18)


Overview of today’s material

- Abstract data types and data structures


- Lists
- Data type functionality

- List data structure implementations:


- ArrayLists
- LinkedLists

- Comparison of implementations
Brief review of key concepts covered last time
Merge Sort
• Divide an array into halves
Sort the two halves
Merge them into one sorted array

• “divide and conquer” algorithm


(Convenient to use recursion)
Merge Sort

Fig. 12-3 The effect of the recursive calls and the


merges during a merge sort.
Carrano and Henry, Data Structures and Abstractions with Java.
Merge Sort time complexity
analysis

• Total levels: log2 (n)


• For each level: merging requires ~n comparisons

 time complexity: O(n*log(n)) What about


Fig. 12-3 The effect of the recursive average/best
calls and thecase?
merges during a merge sort.
Carrano and Henry, Data Structures and Abstractions with Java.
Merge sort summary
• Time complexity - O(n*log(n)) in all cases
• Disadvantages? Space complexity?
• It requires a temporary array for merging operation– O(n)
(compare to many “in-place” sorting algorithms, O(1))
The Quick Sort algorithm
(1) Pick a pivot element
(2) Partition the array:
• Elements less than the pivot are placed to the
left
• Elements greater than the pivot are placed to the
right (Note: array is not necessarily cut in half)
(3) Sort the left and right sub-arrays

Carrano and Henry, Data Structures and Abstractions with Java.


Quick Sort pseudo-code

Algorithm quickSort (a, first, last)


Choose a pivot

Partition the array about the pivot


pivot Index = index of pivot

quickSort (a, first, pivotIndex - 1)


quickSort (a, pivotIndex + 1, last)
}
Quick Sort: partitioning step

A partition strategy for quick sort … continued→

Carrano and Henry, Data Structures and Abstractions with Java.


Quick Sort time complexity analysis
• Consists of one main procedure (partitioning), which is called
recursively
• 1 partitioning step, complexity?
• ~ O(n) (should require no more than n comparisons)

• How many levels of partitioning will there be?


• Ideal case: we pick pivots that split the array in half
log2(n) partitionings (similar to merge sort)
• Worst case?
We pick a pivot that is larger/smaller than all other elements at each step
~ n partitionings

Total worst-case complexity: O(n)*O(n) = O(n2)


Average-case complexity: O(n log n)

Can we avoid the worst-case?


A smarter Quick Sort pivot
selection scheme
Idea: let’s pick a pivot at each for each partition that we know is
not the largest or the smallest
One possibility:
• select three elements randomly (e.g. first, middle, last)
• use the median (middle) value as the pivot

Carrano and Henry, Data Structures and Abstractions with Java.


Quick Sort summary
• Fast sorting algorithm in most cases
• Usually requires less space than merge sort
(average case: O(log n) vs. O(n))
• Variations of Quick Sort are often used in the
“real world”
• Example: remember built-in Java class Arrays,
with static sort methods?
Arrays.sort(intArray);
(quicksort for primitives, mergesort for
reference types)
Carrano and Henry, Data Structures and Abstractions with Java.
Take-home messages on Sorting
• You now know 3 classic sorting algorithms (selection sort,
merge sort, quicksort), their complexities, strengths,
weaknesses
(it’s a good idea to know these by name)
• Which algorithm you use may depend on the context
(example: is space efficiency important?)
• You should be able to implement these on standard data
structures we cover later (e.g. lists with arrays or linked lists)
• In general: you should be able to assess the complexity of a
given algorithm
New material
Overview of today’s material

- Abstract data types and data structures


- Lists
- Data type functionality

- List data structure implementations:


- ArrayLists
- LinkedLists

- Comparison of implementations
Abstract data types and data
structures
Quick review of where we’ve been/where we’re
going
• Essentials of Java programming
• Basics of object-oriented programming
– Modular design
– Encapsulation
– Inheritance
• Now: we want to start applying these concepts to
solve useful and general problems
• One useful problem that shows up everywhere: how
do we efficiently/robustly manage large collections
of data (e.g. student records, user accounts, internet
traffic, genome data, …)
Motivation for data structure design

• Note: data have very specific structures/organization


• These patterns reappear in different applications

We should be able to design “types” (i.e. classes)


that help us organize/process/interact with these
data!
• Design should be motivated by natural structure
of the data + how we want to interact with it
• These types should be general so we can reuse
them in a lot of different settings
Example: the human genome project
• 3.1 billion base pairs (A, T, C, or G) in each cell
• Organized into 20-25,000 genes
We’re also studying not
just these sequences,
but how the
corresponding proteins
interact
(~200 million potential
interactions)

The human protein-protein


interaction network

Rual et al. Towards a proteome-scale map of the human protein–protein interaction network. Nature 437, 1173-1178 (20 October 2005)
A simpler type of data: my weekend to-do list

(1) Register kids for summer camps (Sat 8am)


(2) Take Lucas to soccer
(3) Clean the house
(4) Take Nora to hockey
(5) Read over student’s paper
(6) Go out to dinner (Sat 7pm)

What kind of structure/behavior


does a “list” have?
A closer look at a “list”

• special organizational properties


– has a natural order
– add entries
– remove entries (from anywhere in the list)
– look at any entry
– count how many

• These are also useful characteristics for managing


large amounts of data
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)


What’s the process of defining an abstract data
type and implementing a data structure?
• Much of computer science— defining an idea for a
problem solution, ultimately mapping this to a language
(e.g. Java) that a computer can understand
• Steps:
More abstract (1) Develop specifications for ADT
• What type of data will be stored?
• What are the operations that are possible? How do
they change the data?
(2) Experiment with abstract functionality, iterate spec
definition until complete
Less abstract (3) Formalize specs of the ADT
(4) Implementation of data structure and testing
Developing specifications for a List ADT

• What type of data will be stored?


(not application-specific, but abstractly)

• What are the operations that are


possible?
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.
Example List functionality

Carrano and Henry, Data Structures and Abstractions with Java.


Overview of today’s material

- Abstract data types and data structures


- Lists
- Data type functionality

- List data structure implementations:


- ArrayLists
- LinkedLists

- Comparison of implementations
Array-based implementation of list
data structure
• What member variables will we need?
– array to keep references to object in list
– integer to keep track of current size
– integer to keep track of max size
– ??
• Methods? (need to follow specifications)
public void add(T newEntry) // add to end of list
public T remove(int position) // remove a specific item
public int getLength() // return number of elements in list
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
Implementation of some simple
methods

public int getLength()


{
return numberOfEntries;
} // end getLength

public boolean isEmpty()


{
return numberOfEntries == 0;
// Or getLength() == 0
} // end isEmpty
Implementation of some simple
methods

public int getLength() Note: I’ll cover the implementation


{
return numberOfEntries; details of some of the important
} // end getLength methods, but won’t have time to
cover all during lecture
public boolean isEmpty()
{
return numberOfEntries == 0; See Carrano and Henry, Chapter
// Or getLength() == 0 11 for full details
} // end isEmpty
Implementing add method
Task: Adds newEntry to the end of the list.
Input: newEntry is an object.
Output: None.

public void add(T newEntry) {

}
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
How about this version of add?
public boolean add(int newPosition, int newEntry)

Task: Adds newEntry at position newPosition within the list. Position 1


indicates the first entry in the list.

Input: newPosition is an integer, newEntry is an object.


Output: Reports an error (e.g. throws an exception) if newPosition is
invalid for this list before the operation.

What complications does this version of add introduce?


Adding elements in the middle of
the list
e.g. mylist.add(3,Carla)

Carrano and Henry, Data Structures and Abstractions with Java.


Adding elements in the middle of
the list
e.g. mylist.add(3,Carla)

Solution:
• We need to move everything to the right of the requested
position back by one position in the array
• How about we write a helper method called makeRoom?
Exercise: Implementing
makeRoom helper method
Data members:
list
numberofEntries

private void makeRoom(int givenPosition)


{

}
Exercise: Implementing
makeRoom helper method

private void makeRoom(int givenPosition)


{
int newIndex = givenPosition;
int lastIndex = numberOfEntries;
for (int index = lastIndex; index >= newIndex; index--)
list[index + 1] = list[index];
} // end makeRoom

Carrano and Henry, Data Structures and Abstractions with Java.


Implementing second add method
public boolean add(int newPosition, int newEntry)

Task: Adds newEntry at position newPosition within the list. Position 1


indicates the first entry in the list.

Input: newPosition is an integer, newEntry is an object.


Output: Reports an error (e.g. throws an exception) if newPosition is
invalid for this list before the operation.

(use your makeRoom method)


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)

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
removeGap helper method

// Shifts entries that are beyond the entry to be removed to the


// next lower position.
// Precondition: 1 <= givenPosition < numberOfEntries;
// numberOfEntries is list's length before removal;
// checkIntegrity has been called.
private void removeGap(int givenPosition)
{
int removedIndex = givenPosition;
for (int index = removedIndex; index < numberOfEntries; index++)
list[index] = list[index + 1];
} // end removeGap
Reviewing our array-based List
implementation
• Basic data members
• Basic operations: add, remove, getLength,
isEmpty

• Major limitation: our code assumes a fixed


size array that can get full—how can we
update this?
Addressing the fixed array length
limitation
• Idea: when we do an “add” to our list, let’s
check if our array is almost full
– If yes, just double the size of the array, copy the
elements over into new array
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)
Note on Java’s “List” interface
public void add(int index, T newEntry)
java.util.List
public T remove(int index)
public void clear()
public T set(int index, T anEntry) // Like replace
public T get(int index) // Like getEntry
public boolean contains(Object anEntry)
public int size() // Like getLength
public boolean isEmpty()
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/List.html

Built-in Java class that implements List interface: java.util.ArrayList


https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ArrayList.html

Example:
List<String> stringList = new ArrayList<String>();
stringList.add(0,"string1")
stringList.add(1,"string2")
Overview of today’s material

- Abstract data types and data structures


- Lists
- Data type functionality

- List data structure implementations:


- ArrayLists
- LinkedLists

- Comparison of implementations
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
Waiting room analogy

• Patients come in, check in, are maintained on an ordered list


• Array implementation: receptionist uses a piece of paper to order
the list

• Linked list implementation: receptionist just remembers one


patient (the first one); each patient remembers the person who
came in immediately after them
Linked Data

Carrano and Henry, Data Structures and Abstractions with Java.


Forming a Linked list by adding to end

• First patient comes in, receptionist remembers which


seat they’re sitting in (10)

Carrano and Henry, Data Structures and Abstractions with Java.


Forming a Linked list by Adding to End
• Second patient arrives
• Recetionist passes
the patient off to the
original patient

• Original patient has


the responsibility of
remembering the next
patient (in seat 4),
writes the number
down

Carrano and Henry, Data Structures and Abstractions with Java.


Forming a Linked list by Adding to End

• Third patient arrives


• Receptionist passes the
patient off to the original
patient, who passes them
down the line

• The second patient (seat


4) needs to remember the
newest patient (seat 20),
writes the number down

Carrano and Henry, Data Structures and Abstractions with Java.


Forming a Linked list by Adding to End

Carrano and Henry, Data Structures and Abstractions with Java.


More sophisticated operations on our
linked list
• What happens if we get a patient who needs
immediate attention?

First What logic has


patient to happen for the
“urgent”
receptionist to
patient
maintain the
order?
Adding an element in the middle of a
linked list

First
patient

“urgent”
patient

• receptionist only remembers


“urgent” patient
• “urgent” patient needs to
remember the original first patient
Carrano and Henry, Data Structures and Abstractions with Java.
Adding an element in the middle of a
linked list
“somewhat
urgent” patient

Patient after

Patient before

What’s the logic here?


Carrano and Henry, Data Structures and Abstractions with Java.
Forming Chain by Adding at Various
Positions
“somewhat
urgent” patient

Patient after

• patient 20 needs to switch


who he/she remembers
Patient before (now 12)
• new patient needs to
remember the link to the
rest of the list
Carrano and Henry, Data Structures and Abstractions with Java.
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 Class
• An inner class that will contain a single element in
our list
– Inner class: a class defined within another class definition
• Nodes linked together + the methods will form our
linked list data structure
• Two data fields:
– A reference to an entry in the list
– A reference to another node

Carrano and Henry, Data Structures and Abstractions with Java.


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 rest of the
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()
First, some easy methods

public class LList<T> implements ListInterface<T> {

// everything else…
public int getLength(){ return length; }

public void clear(){


firstNode = null;
length = 0; }

public boolean isEmpty(){ return length==0;}

}
Adding elements to a linked list
• First, remember back to array
implementation:

public void add(T newEntry)


{

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

}
} // end add
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
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

- Abstract data types and data structures


- Lists
- Data type functionality

- List data structure implementations:


- ArrayLists
- LinkedLists

- Comparison of implementations
Comparison of array and linked list List
implementations

• Which is better?
– Memory?

– Speed?

Assume N elements– what’s the number of operations in the worst case?


Comparison of array and linked list List
implementations

• Which is better?
– Memory?
• 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?

– Speed?
• 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?

– Speed?
• 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?

– Speed?
• 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
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
getNodeAt method

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;
}

}
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 the tail
} // end add reference
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

You might also like