Linked Lists: CS221N, Data Structures
Linked Lists: CS221N, Data Structures
1
Recall Arrays
Advantages
Access is fast – O(1)
Insertion is fast in an unordered array O(1)
Searching is fast in an ordered array – O(log n)
Because we can apply the binary search
Disadvantages
Deletion is slow – O(n)
Searching is slow in an unordered array – O(n)
2 Insertion is slow in an ordered array – O(n)
Recall stacks and queues
Not generally used for real-world data
storage
Why?
We also saw last week that for stacks and queues, you could use arrays as an
underlying data structure
You also can use linked lists!
4
Several Types
Simple
Double-ended
Sorted
Doubly-linked
Lists with iterators
5
A Link
Data in linked lists are embedded in links
Each link consists of:
The data itself
A reference to the next link in the list,
which is null for the last item
6
The Link class
It makes sense to make Link its own class,
since a list can then just be a collection of
Link objects:
This is sometimes called a self-
referential class. Any theories why?
7
class Link {
References
Remember in Java, all objects are references
That means that the variable ‘next’, for each link just contains an integer for a memory
address
A ‘magic number’ which tells us where the object is
They are always the same size (so no problem)
8
Memory
How would this look in memory then?
Let’s draw it on the board.
9
Recall the implication!
Access for linked lists is slow compared to
arrays
Arrays are like rows of houses
They are arranged sequentially
So it’s easy to just find, for example, the
third house
With linked lists, you have to follow links
10
Links of Records
We can have a link of personnel records:
class Link{
public String name;
public String address;
public int ssn;
public Link next;
}
We can also have a class for PersonnelRecords, and a linked list of those. Let’s
do that together!
11
Operations
Insertion
At the beginning (fast)
In the middle (slower, although still
better than arrays)
Deletion
At the beginning (fast)
In the middle (slower, although still
12
LinkedList class
Start with:
A private Link to the first element
A constructor which sets this reference to
null
A method isEmpty() which returns true if
the list is empty
13
insertFirst(): O(1)
Accept a new integer (p. 188)
Create a new link
Change the new link’s next reference to
the current first
Change first to reference the new link
We could not execute these last two in
14
reverse. Why?
deleteFirst(): O(1)
Remove the first integer in the list (p. 188)
Just reset the first reference to first.next
15
displayList() – p. 189 O(n)
Use a reference current to iterate through
the elements
Print the value
Set current to current.next
Stop when current becomes null
Before setting current to current.next:
16
main() function
LinkedList theList = new LinkedList();
theList.insertFirst(22);
theList.insertFirst(44);
theList.insertFirst(66);
theList.insertFirst(88);
theList.displayList();
while (!theList.isEmpty())
theList.deleteFirst();
theList.displayList();
17
find() – p. 194 O(n)
Essentially the same idea as displayList()
Linearly iterate through the elements
with a reference current
Repeatedly set current to current.next
Except this time, stop when you find the
item!
Before setting current to current.next:
18
delete() – p. 194 O(n)
Pass a value stored in the list, and remove
it
First we have to find it, at that point it will
be in current
Set the previous element’s next reference
to current.next
When we find the value:
19
main() function - #2
LinkedList theList = new LinkedList();
theList.insertFirst(22);
theList.insertFirst(44);
theList.insertFirst(66);
theList.insertFirst(88);
theList.displayList();
Link f = theList.find(44);
theList.delete(66);
theList.displayList();
20
Double-Ended Lists
Just like a regular linked list, except there
are now two references kept
One to the beginning (first)
And one to the end (last)
Enables easy insertion at both ends
You still cannot delete the last element
21
any easier. Why?
insertLast() – p. 199 O(1)
What does this look like now? Let’s see:
Create the new link with the new value
(next=null)
Set last.next to reference the new link
Set last to reference the new link
Might we also have to set first? When?
22
main() function - #3
LinkedList theList = new LinkedList();
theList.insertFirst(22);
theList.insertFirst(44);
theList.insertFirst(66);
theList.insertLast(11);
theList.insertLast(33);
theList.insertLast(55);
theList.displayList();
23
Double-Ended Lists
Would we also have to modify delete()?
When? Let’s do it.
24
Efficiency: Summary
Fast insertion/deletion at ends: O(1)
Searching: O(n)
Deleting a specific item: O(n)
BUT, faster than arrays
You have equal O(n) for the search
But then an array requires an O(n) shift,
25
where a list requires reference copies –
Memory: Summary
A linked list uses (more or less) memory
than an array? Why?
27
Data Types
Examples of data types: int, float double
These are called primitive data types
When we refer to a datatype:
Characteristics of the data
Operations which you can perform on
that data
Object-oriented programming defines
28
Abstraction
Abstract: Considered apart from detailed
specifications or implementation.
Let’s ponder the following questions:
What is an analogy of abstraction in the
English language?
How does abstraction equate to datatypes
29
and operations?
Abstract Data Types (ADTs)
Idea: Represent a Data Structure by
focusing on what it does and ignoring how
it does it.
We’ve seen this already with stacks and
queues
Internally, they stored data as an array
But the user didn’t know this! All they
30
Revisiting the stack….
LIFO structure
Items are inserted, removed
and accessed from the top
31
Revisiting the queue…
FIFO structure
Items are inserted from the rear and removed from the front
32
When to use which?
List is clearly the better choice when you
(know or do not know?) the number of
elements that the stack or queue will hold
Analyze: what are the tradeoffs
In the case of the queue, a linked list saves
us the concern of wraparound
Keeping track of two references, front
33
Summary: ADTs
In Software Engineering
It’s always important to consider the operations you want before you determine
details, like:
Memory
Implementation of functions
For example, the operations you desire will strongly determine the data structure
you use
First item? Last item? Item in a certain position?
34
Sorted Lists
Linked list where the data is maintained in
sorted order
Useful in some applications
Same applications where you’d use a
sorted array
But, insertion will be faster!
And, memory will be used more
35
insert() p. 214 O(n)
We haven’t looked at inserting
in the middle. Let’s see how it
will be done:
36
main() function - #4
LinkedList theList = new LinkedList();
theList.insert(20);
theList.insert(40);
theList.displayList();
theList.insert(10);
theList.insert(30);
theList.insert(50);
theList.displayList();
theList.remove();
37 theList.displayList();
Sorted Linked List: Efficiency
Insertion and deletion are O(n)
for the search worst case
Cannot do a binary search on
a sorted linked list, like we
could with arrays! Why not?
Minimum value can be found
in O(1) time
38
Limitation: Previous element
Numerous times, we found the inability to access the previous element inconvenient
Double-ended list and deleting the last element
Could not search from both ends
39
Our new Link class
class Link
{
public int iData;
public Link previous;
public Link next;
}
40
Pictorally…
Single-ended (‘L’ references the List)
44
insertFirst() O(1)
Steps
Create a new link
Set its next reference to first
Set first’s previous reference to the new
link
Set first (and last if empty) to reference
45
the new link
insertLast() O(1)
Steps
Create a new link
Set it previous reference to last
Set last’s next reference to the new link
Set last (and first if empty) to reference
the new link
Before
46
insertAfter() O(n)
Steps
Find the element in the list to insert after
(current)
Set current.next’s previous reference to
the new link
Set link’s next reference to current.next
Set current.next to the new link
47
deleteFirst() O(1)
Steps
Set first.next’s previous reference to null
Remember first.next could be null!!
Set first to first.next
Before
48
deleteLast() O(1)
Steps
Set last.previous’ next reference to null
Remember last.previous could be null!!
Set last to last.previous
Before
49
deleteKey() O(n)
Steps
Find the key, call it current
Set current.previous’ next
reference to current.next
Set current.next’s previous
reference to current.previous
Be sure to handle the case when
50
either is null!! This would be
displayForward() O(n)
Use a reference current to iterate through
the elements
Initially equal to first, print the value
Set current to current.next
Stop when current becomes null
Before setting current to current.next:
51
displayBackward() O(n)
Use a reference current to iterate through
the elements
Initially equal to last, print the value
Set current to current.previous
Stop when current becomes null
Before setting current to current.previous:
52
Iterators
What have we seen?
Ability to linearly traverse a
list and find an item
What have we been missing?
Control over the items we
traverse
53
Idea
Provide a class which:
Contains a reference to some element in
the list
Can easily increment itself to reference
the next element
54 class ListIterator() {
main() function - #4
LinkedList theList = new
LinkedList();
ListIterator iter = new
ListIterator(theList.getFirst());
56
Bidirectional Iterators
If we have a doubly-linked list, it’s easy.
Let’s add two methods to our previous
iterator class:
One to access the previous Link
prevLink()
59
ListIterator: p. 237
Let’s now change the ListIterator
Make it bidirectional
Contain a reference to the list, as opposed to a single link
Methods
ListIterator(): Pass a LinkedList reference, and set
reset(): Reset iterator to the beginning of the list
atEnd(): Check if we are at the end
nextLink(): Move to the next link
getCurrent(): Return the current link
insertAfter(): Insert a link after the link referenced
insertBefore(): Insert a link before the element referenced
deleteCurrent(): Delete the currently referenced link
60
deleteCurrent(): Notes
If we delete an item, where should the
iterator now point?
We’ve deleted the item it was pointed to!
We don’t want to move it to the
beginning
Concept of ‘locality’
Can’t move it to the previous item
61
atEnd(): Notes
Our implementation checks if the iterator
points to the last element. Tradeoffs:
Looping becomes awkward
Iterator is always pointing at a valid link,
which is good for reliability
Must be careful with iteration
Let’s say we used a loop to display data
62
Another example
Deleting all links that contain values with
multiples of three. How can we use the
iterator to do this?
63