Title: Chapter 4 Linked Lists
1Chapter 4Linked Lists
- CS 260 Data Structures
- Indiana University Purdue University Fort Wayne
2Linked lists
- A linked list is a sequence of nodes in which
each node contains a link (i.e., a reference
variable) to the next node - Each node is an object consisting of info and
the link - The info could be primitive data or a reference
to another object
info link
3Linked lists
13
head tail
7
19
null reference
Note the tail reference is optional
head tail
Empty linked list
4Linked lists
- Advantages
- Memory added only incrementally
- More flexible than an array
- Disadvantages
- Wastes storage for the links
- Added complexity
- No random access as with an array
- Linked lists offer an attractive alternative to
arrays in many situations
5A class for nodes
public class IntNode private int
data private IntNode link public
IntNode( int initData, IntNode initLink )
data initData link initLink
? ? ? // end class IntNode
- Note that this class definition is
self-referencing - This is similar to recursion
- Java allows this
6Basic behavior of class IntNode
- Constructor
- getData
- getLink
- setData
- setLink
7Use of linked lists
- Build and output a linked list containing the
integers 1, 2, 3, , 100
IntNode head null IntNode tail
null head new IntNode( 1, head ) tail
head for ( int i 2 i lt 100 i ) head
new IntNode( i, head )
1
head tail
2
head tail
1
100
head tail
99
98
3
2
1
? ? ?
8Output of the linked list
for ( IntNode cursor head cursor ! null
cursor cursor.getLink() )
System.out.println( cursor.getData() )
100
head tail
99
98
3
2
1
? ? ?
- This statement outputs the values in the linked
list in the order 100, 99, 98, , 3, 2, 1 - The list was built by adding new nodes to the
head - But how could we build the list so that the
values are output is in the order created? - Build the list by adding new nodes to the tail
9Build the list by adding to the tail
IntNode next head new IntNode( 1, null ) tail
head for ( int i 2 i lt 100 i )
next new IntNode( i, null ) tail.setLink(
next ) tail next
1
head tail
1
head tail
2
next
1
head tail
2
3
98
99
100
? ? ?
next
10Enhancing class IntNode
- We have been working from outside the IntNode
class - Need methods getData, setLink, etc.
- It is better to add useful operations to IntNode
that work from the inside
11Method addNodeAfter
public IntNode addNodeAfter( int element )
link new IntNode( element, link ) return
link
Note Method returns a pointer to the node added,
in contrast to a similar text method (page 179)
Insert an IntNode containing 23 after the node
referenced by p p.addNodeAfter( 23 )
p
17
11
81
3
? ? ?
? ? ?
23
12Build the list again using the new method
IntNode next head new IntNode( 1, null ) tail
head for ( int i 2 i lt 100 i )
tail tail.addNodeAfter( i )
1
head tail
1
head tail
2
1
head tail
2
3
98
99
100
? ? ?
13Method removeNodeAfter
public IntNode removeNodeAfter( ) link
link.link
- Note there is a distinction between link. and
link - Link is the primitive reference variable
- Link. is the object link refers to !
p
p.removeAfter()
link.
link
17
11
81
3
? ? ?
? ? ?
14Method removeNodeAfter
- To use removeNodeAfter, a reference to a node
just before the node to be removed must be set up
- The removed node becomes inaccessible
- (unless, of course, an alias has been made of
the node) - Garbage collection
- A Java run-time system periodically finds and
recycles inaccessible storage - Caution tail.removeNodeAfter causes a
NullPointerException()
15Static methods for the IntNode class
- There are 6 static methods
- listCopy
- listCopyWithTail
- listLength
- listPart
- listPosition
- listSearch
- Each of these operates on an entire list
- They would be more properly implemented as
instance methods in a new IntList class having
entire lists as objects
16Usage of the static methods
n IntNode.listLength( head ) // returns
the size of the list
newList IntNode.listCopy( head ) // Clones the
list and returns a pointer to the clone
selection IntNode.listSearch( head, 19 ) //
Searches the list starting with head for a node
containing 19 // Returns a pointer to the node
if successful, otherwise returns null
selection IntNode.listPosition( head, 19 ) //
Searches the list starting with head for a node
at position 19 // Returns a pointer to the node
if successful, otherwise returns null //
Position numbers start with 1, not 0
17Static methods for the IntNode class
- listCopyWithTail and listPart both return two
pointers - References to both the head and tail of a list
- How?
- Return a 2-cell array copyInfo
- copyInfo 0 refers to the head
- copyInfo 1 refers to the tail
18Usage of the static methods
- IntNode copyInfo
- copyInfo IntNode.listCopyWithTail( head )
- // Clones the list and returns head and tail
pointers to the clone - // copyInfo 0 points to the head of the clone
- // copyInfo 1 points to the tail of the clone
- IntNode copyInfo
- copyInfo IntNode.listPart( startNode,
finishNode ) - // Clones the part of the list from startNode to
finishNode - // startNode and finish node must be nodes in the
list - // startNode must preceed finishNode
- // Returns head and tail pointers to the cloned
part - // copyInfo 0 points to the head of the clone
- // copyInfo 1 points to the tail of the clone
19Methods listLength and listSearch
public static int listLength( IntNode head )
IntNode cursor int answer
answer 0 for ( cursor head cursor
! null cursor cursor.link )
answer return answer
Note there is a trade-off in not having an
instance variable like manyItems
public static IntNode listSearch( IntNode head,
int target ) IntNode cursor for (
cursor head cursor ! null cursor
cursor.link ) if ( target cursor.data
) return cursor return null
20Method listPosition
public static IntNode listPosition( IntNode head,
int position ) IntNode cursor int
i if ( position lt 0 )
throw new IllegalArgumentException( "position is
not positive ) cursor head for (
i 1 ( i lt position ) ( cursor ! null )
i ) cursor cursor.link return
cursor
This method returns null if position is beyond
the end of the list
21Method listCopy
public static IntNode listCopy( IntNode source )
IntNode copyHead IntNode
copyTail if ( source null )
return null copyHead new
IntNode( source.data, null ) copyTail
copyHead while ( source.link ! null )
source source.link copyTail
copyTail.addNodeAfter( source.data )
return copyHead
22Method listCopyWithTail
public static IntNode listCopyWithTail(
IntNode source ) IntNode copyHead
IntNode copyTail IntNode answer new
IntNode 2 if ( source null )
return null copyHead new
IntNode( source.data, null ) copyTail
copyHead while ( source.link ! null )
source source.link copyTail
copyTail.addNodeAfter( source.data )
answer 0 copyHead answer 1
copyTail return answer
23Method listPart
public static IntNode listPart( IntNode start,
IntNode end ) IntNode copyHead
IntNode copyTail IntNode answer new
IntNode 2 if ( start null )
throw new IllegalArgumentException( start is
null ) if ( end null ) throw
new IllegalArgumentException( end is null )
copyHead new IntNode( start.data, null )
copyTail copyHead while ( start !
end ) start start.link if
( start null ) throw new
IllegalArgumentException( end node was not found
on the list ) copyTail
copyTail.addNodeAfter( start.data )
answer 0 copyHead answer 1
copyTail return answer
24Applications of linked lists
- Our applications are to develop bag and sequence
classes using linked lists instead of arrays - IntLinkedBag
- DoubleLinkedSeq
- In each case, the data structure should appear to
be essentially the same to the user - The goal is to allow an application to use the
new implementation by only changing the name of
the class being used - Names of methods should not change
25Class IntLinkedBag
- This is the bag ADT implemented with a linked
list - See text pages 208 225 for details
- State
- private IntNode head
- private int manyNodes
- ADT invariant of the IntLinkedBag class (see
textbook, p. 212) - The elements of the bag are stored in a linked
list. - The head reference of the list is stored in the
instance - variable head.
- 3. The total number of elements in the list is
stored in the - instance variable manyNodes
26Class IntLinkedBag
- Behavior summary
- Eliminate methods
- getCapacity
- ensureCapacity
- trimToSize
- These have nothing to do with a bag as an ADT
- Should these have been included in IntArrayBag?
- New method grab
- grab returns an element selected at random by a
random number generator - Could grab have been included in IntArrayBag?
27Class IntLinkedBag
- Note that there is trade-off in including the
instance variable manyNodes - Without a partially-filled array, something like
manyItems is no longer needed - The static method listLength(? ? ?) could be used
to implement the size( ) method - This would simplify the ADT invariant for the
class - But on the other hand, O( size ) is then linear
rather than constant
28Class IntLinkedBag
- Constructor
- Method add
- Since order is not important, new elements may be
added at the head of the list
public IntLinkedBag( ) head null
manyNodes 0
public void add( int element )
head new IntNode( element, head )
manyNodes
29Method remove
public boolean remove( int target )
IntNode targetNode // The node that contains
the target targetNode IntNode.listSearch(
head, target ) if ( targetNode null
) // The target was not found return
false else // The target was found at
targetNode // Copy the head data to
targetNode and then remove the extra copy
targetNode.setData( head.getData( ) )
head head.getLink( ) manyNodes--
return true
30Method remove
- Just after IntNode.listSearch
- After return
manyNodes head targetNode
5
19
target
33
11
19
92
56
4
19
manyNodes head targetNode
target
33
11
33
92
56
31Method remove
- Does it work if the head element, 33, is removed?
- Boundary case
4
33
manyNodes head targetNode
target
33
11
19
92
56
32Method addAll
public void addAll( IntLinkedBag addend )
IntNode copyInfo // The node that
will refer to the target if ( addend
null ) throw new IllegalArgumentException
( Addend is null. ) if (
addend.manyNodes gt 0 ) copyInfo
IntNode.listCopyWithTail( addend.head )
copyInfo1.setLink( head ) // Link the tail
of copy to my own head... head
copyInfo 0 // and set my own
head to the head of the copy. manyNodes
manyNodes addend.manyNodes
33Method addAll
- Perform a.allAll( b ) for bags a and b
- The addend bag is b
10
20
30
a.head
40
50
b.head
copyInfo
40
50
O 1
34Class DoubleLinkedSeq
- This is the sequence ADT implemented with a
linked list - See text pages 225 231
- State
- private DoubleNode head
- private DoubleNode tail
- private DoubleNode cursor
- private DoubleNode precursor
- private int manyNodes
35Class DoubleLinkedSeq
33
11
19
92
56
head tail cursor
precursor manyNodes
5
- The precursor always points to the node just
before the cursor
36Class DoubleLinkedSeq
- ADT invariant of the DoubleLinkedSeq class
- The elements of the sequence are stored in a
linked list - The total number of elements in the list is
stored in the instance variable manyNodes - If the list is not empty, head refers to the
first element in the list otherwise it is the - null reference
- 4. If the list is not empty, tail refers to the
last element in the list otherwise, it is the - null reference
- 5. If there is a current element, that element is
referred to by cursor - otherwise, cursor is the null reference
- 6. If there is a current element and it is not
the first element, then precursor refers to the - element just before the current element,
otherwise precursor is the null reference - 7. When a new element is added, it becomes the
new current element - 8. When an element is removed or advance is
applied, the following element is current - if no following element exists, there is no
current element
37A DoubleLinkedSeq method
- Recall . . .
- Method addBefore adds a new element to a sequence
- If there is a current element, addBefore places
the new element before the current element - If there is no current element, addBefore places
the new element at the front of the sequence - The new element always becomes the new current
element of the sequence
38Method addBefore
public void addBefore( double element )
if ( ( precursor null ) // either no
current element or current element is first
// add element to the head of the list
head new IntNode( element, head )
cursor head else
// cursor
points to the middle of the list
precursor.setLink( new IntNode( element, cursor )
) cursor precursor.getLink()
if ( manyNodes 0 ) // the
list was empty and tail needs to be initialized
tail head manyNodes
- Is precursor OK when adding at head?
- Is tail OK when cursor tail?
39Beyond simple linked lists
- Doubly-linked lists
- Nodes have two pointers
- Doubly-linked lists have the form . . .
backLink data foreLink
33
19
23
87
head
40Beyond simple linked lists
- Dummy list heads
- List head is never null
- Empty linked list
- Methods may often be simplified using dummy list
heads - Example Inserting an element at the logical
beginning of a list is the same as inserting the
element in the middle of the list - A dummy list heads may be used in conjunction
with a doubly-linked list
11
19
92
56
head
dummy
head
dummy
41Linked list and array trade-offs