05. Linked Lists

advertisement
241-423 Advanced Data Structures
and Algorithms Semester 2, 2013-2014
5. Linked Lists
• Objective
– implement and use linked lists
241-423 ADSA: Linked Lists/5
1
Contents
1. An ArrayList can be Slow
2. What is a Linked List?
3. Java Assignment Differences
4. Implementing a Linked List
5. Using a Linked List
6. Doubly Linked Lists
7. The (Doubly) LinkedList Collection
8. Palindromes
241-423 ADSA: Linked Lists/5
2
1. An ArrayList can be Slow
• Inserting/removing an element inside an
ArrayList requires data shifting
– O(n) operations
241-423 ADSA: Linked Lists/5
3
2. What is a Linked List?
• Each element (node) inside a linked list is
linked to the previous node and successor
(next) node.
• This allows for more efficient insertion and
deletion of nodes. Why?
5
241-423 ADSA: Linked Lists/5
3
14
2
continued
4
• Inserting a new node only involves breaking
one link, and linking the list to both ends of the
new node:
– all are O(1) operations
241-423 ADSA: Linked Lists/5
continued
5
• Removal of a node only requires the breaking
of its two links, removal of the node, and then
the relinking of the list:
– all are O(1) operations
241-423 ADSA: Linked Lists/5
continued
6
• The insertion/removal of a node is a local
operation
– only the links next to the node need to be changed
– the other nodes in the list are not affected
– fast: O(1)
• An ArrayList must shift lots of elements
when an element is inserted/removed
– slow: O(n)
241-423 ADSA: Linked Lists/5
7
3. Java Assignment Differences
Foo a = new Foo();
Foo b;
b = a;
a
b
copy the link
(the reference)
Foo object
32
a
241-423 ADSA: Linked Lists/5
int a = 32;
int b;
b = a;
copy the value
32
b
8
4. Implementing a Linked List
• Each node is an object containing a value and
a link (reference) to the next node (object) in
the list
– a singly-linked
list
• The list uses a 'front' variable to point to
the first object in the list.
• The reference in the last object is null.
241-423 ADSA: Linked Lists/5
9
Accessing a Node
• Nodes in a singly-linked list are accessed by
moving forward one node at a time from the
front
– called sequential access
– a linked list is not a direct access structure like an
array
– this means that access is slower than in an array
•
•
linked list access (if index is known): O(n)
array list access (if index is known): O(1)
241-423 ADSA: Linked Lists/5
10
Nodes in a Linked List
• Each Node object contains two variables:
– nodeValue, of generic type T
– next, a reference that links to the next node
241-423 ADSA: Linked Lists/5
11
The Node Class
public class Node<T>
{
public T nodeValue;
public Node<T> next;
// data held by the node
// next node in the list
public Node()
{ nodeValue = null;
next = null;
}
public Node(T item)
{ nodeValue = item;
next = null;
}
}
241-423 ADSA: Linked Lists/5
12
• The variables in the Node class are public to
simplify the coding using linked lists
– bad style (from Ford & Topp, not me ☺)
• The Node class is self-referencing:
– next refers to (points to) an object of the same
type
241-423 ADSA: Linked Lists/5
13
Creating a Linked List
// create two nodes (figure (a)
Node<String> p = new Node<String>("red");
Node<String> q = new Node<String>("green")
// link p to q
p.next = q;
// figure (b)
// set front to point at the first node
Node<String> front = p;
// figure (c)
green
red
p
q
(a) Create nodes p and q
241-423 ADSA: Linked Lists/5
red
green
p
(b) Link p to q
q
front
red
green
p
q
(c) Assign front to point at p (red)
continued
14
• If the linked list is empty, front is assigned
null.
241-423 ADSA: Linked Lists/5
15
Scanning a Linked List
• We scan a singly linked list by starting at
the front, and then move along the list one
Node at a time
– sequential access (O(n))
– stop when we reach null
• toString() is an example of a scanning
method, which builds a string as it moves
along the list.
241-423 ADSA: Linked Lists/5
16
toString()
public static <T> String toString(Node<T> front)
// build a string from the list of the form
//
"[ n1, n2, ..., nx ]"
{
if (front == null)
// empty list
return "[]";
Node<T> curr = front;
// start at the front
String s = "[" + curr.nodeValue;
while(curr.next != null) {
curr = curr.next;
// move along list
s += ", " + curr.nodeValue;
}
s += "]";
return s;
}
241-423 ADSA: Linked Lists/5
17
Moving to a List Position
• To move to an element at position x, we
need to start at the front and move through
the list counting up to x
– sequential access again (O(n))
• The first element of the list is at position 0.
241-423 ADSA: Linked Lists/5
continued
18
Node<T> curr = front;
// start at the front of list
for (int i = 0; i < xPos; i++)
curr = curr.next;
// move along list
pos 0
pos 1
pos 2
front
pos 3
pos 3
front
curr
curr
Assign curr to front
241-423 ADSA: Linked Lists/5
Move curr with 3 iterations
19
Updating the Front of the List
• Inserting or deleting an element at the front of
a list is easy (and fast) because the 'front'
variable always points to the first element:
– the operations are O(1)
241-423 ADSA: Linked Lists/5
20
Insert at the Front
Node<T> newNode = new Node<T>(item);
// insert item at the front of the list
newNode.next = front;
front = newNode;
//
front
item
newNode
241-423 ADSA: Linked Lists/5
21
Delete from the Front
front = front.next;
// move front to next node
//
front
front.next
241-423 ADSA: Linked Lists/5
22
General Insertion
• To insert a new node before a node referenced
by 'curr', the code must have access to the
previous node, 'prev', since its link must be
changed.
241-423 ADSA: Linked Lists/5
continued
23
Node<T> curr =
Node<T> prev =
... // set to point to a node
... // set to point to previous node
Node<T> newNode = new Node<T>(item);
// update links
newNode.next = curr;
prev.next = newNode;
241-423 ADSA: Linked Lists/5
// new node
// step 1
// step 2
continued
24
• The insertion is O(1) since only two links
need to be changed. But the real cost is the
sequential search to find the insertion
position, which is O(n).
241-423 ADSA: Linked Lists/5
25
General Deletion
• Deleting a node at position curr requires access
to the predecessor node prev.
Node<T> curr =
Node<T> prev =
... // set to point to a node
... // set to point to previous node
// connect prev to curr.next
prev.next = curr.next;
curr.next = null;
241-423 ADSA: Linked Lists/5
continued
26
• The deletion is O(1) since only two links
need to be changed. But the real cost is the
sequential search to find the deletion
position, which is O(n)
– this is shown in the remove() method, which is
explained next
241-423 ADSA: Linked Lists/5
27
Removing a Target Node
• To remove the first node having a specified
value, scan the list to find the node.
• The scan must use two references that move
together down the list
– one reference (curr) points to the current node in
the scan
– the other reference (prev) points to the previous
node
241-423 ADSA: Linked Lists/5
continued
28
• Once 'curr' finds the node, the code uses
'prev' to unlink 'curr'.
241-423 ADSA: Linked Lists/5
continued
29
• At the start, point 'curr' at the front of the list
and set 'prev' to null, since the first node does
not have a predecessor.
• Move 'curr' and 'prev' down the list until
curr.nodeValue matches the target or
curr == null.
241-423 ADSA: Linked Lists/5
continued
30
• If the target is found then 'curr' points at the
node and 'prev' to the predecessor node.
• But there are two possible cases:
– the target node is the first node, so 'prev' is null
– the target node is not the first node, so 'prev' points
to something
241-423 ADSA: Linked Lists/5
continued
31
• Case 1: 'prev' is null which means that 'curr'
points to the first node.
– so we only have to delete the front of the list
front = curr.next;
curr.next = null;
241-423 ADSA: Linked Lists/5
32
• Case 2: The match occurs in the middle of the
list. Both 'curr' and 'prev' have non-null values.
Unlink the current node.
prev.next = curr.next;
curr.next = null;
241-423 ADSA: Linked Lists/5
continued
33
• The generic remove() is passed a reference to
the front of the list and the target value.
• The method returns the value of 'front', which
may have been updated if the first node was
deleted.
241-423 ADSA: Linked Lists/5
34
remove() Method
public static <T> Node<T> remove(Node<T> front, T target)
/* Delete the first occurrence of the target in the
linked list referenced by front; return the
value of front */
{
// initialize pointers
Node<T> curr = front;
Node<T> prev = null;
boolean foundItem = false;
// set to true if we find the target
:
241-423 ADSA: Linked Lists/5
35
}
// scan until find item or end of list (O(n))
while (curr != null && !foundItem) {
// check for a match
if (target.equals(curr.nodeValue)) {
if (prev == null)
// remove first Node (O(1))
front = front.next;
else
// erase middle Node (O(1))
prev.next = curr.next;
curr.next = null;
foundItem = true;
}
else { // advance curr and prev
prev = curr;
curr = curr.next;
}
}
return front; // may be updated
// end of remove()
241-423 ADSA: Linked Lists/5
36
5. Using a Linked List
import java.util.Random;
import java.util.Scanner;
import ds.util.Node;
import ds.util.Nodes;
// methods using Node<T>
public class ListExample
{
public static void main(String[] args)
{
// the initial list is empty
Node<Integer> front = null;
Random rnd = new Random();
Scanner keyIn = new Scanner(System.in);
:
241-423 ADSA: Linked Lists/5
37
System.out.print("Enter the size of the list: ");
int listCount = keyIn.nextInt();
// create a list
Node<Integer> newNode;
for (int i = 0; i < listCount; i++) {
newNode = new Node<Integer>(rnd.nextInt(100));
newNode.next = front;
// insert at list front
front = newNode;
}
System.out.print("Original list: ");
System.out.println( Nodes.toString(front) );
:
241-423 ADSA: Linked Lists/5
38
System.out.print("Ordered list:
}
");
Node<Integer> p;
while (front != null) { // list not empty
p = getMaxNode(front);
// get largest
System.out.print(p.nodeValue + " ");
front = Nodes.remove(front, p.nodeValue);
}
System.out.println();
// end of main()
241-423 ADSA: Linked Lists/5
39
public static <T extends Comparable<? super T>>
Node<T> getMaxNode(Node<T> front)
{
Node<T> maxNode = front;
// initial values
Node<T> curr = front.next;
T maxValue = front.nodeValue;
while (curr != null) {
// try to update maxNode and maxValue
if (maxValue.compareTo(curr.nodeValue)< 0) {
maxValue = curr.nodeValue;
maxNode = curr;
}
curr = curr.next;
}
return maxNode;
} // end of getMaxNode()
}
// end of ListExample class
241-423 ADSA: Linked Lists/5
40
Execution
241-423 ADSA: Linked Lists/5
41
6. Doubly Linked Lists
• A node in a doubly-linked list contain two
references that point to the next node and the
previous node.
• front points to the first node in the list
• back points at the last node in the list
241-423 ADSA: Linked Lists/5
continued
42
• A doubly-linked list can be scanned in both
directions:
– a forward scan starts at 'front' and ends when the
link is to the same object as 'back'
– a backward scan starts at 'back' and ends when the
link is to the same object as 'front'
241-423 ADSA: Linked Lists/5
continued
43
• Like a singly-linked list, a doubly linked list is
a sequential structure.
• To move forward or backward, use the node
links 'next' and 'prev'.
• Unlike a singly linked list, the insert and delete
operations only need a single reference to the
node.
241-423 ADSA: Linked Lists/5
continued
44
• Insertion into a doubly linked list requires four
reference assignments.
prevNode = curr.prev;
newNode.prev = prevNode;
prevNode.next = newNode;
curr.prev = newNode;
newNode.next = curr;
241-423 ADSA: Linked Lists/5
//
//
//
//
1
2
3
4
continued
45
• To delete a node curr, link the predecessor
(curr.prev) of 'curr' to the successor of 'curr'
(curr.next).
prevNode = curr.prev;
succNode = curr.next;
succNode.prev = prevNode;
prevNode.next = succNode;
curr.prev = null;
curr.next = null;
241-423 ADSA: Linked Lists/5
// 1
// 2
continued
46
• In a singly-linked list, adding and removing a
node at the front of the list are O(1) operations.
• With a doubly linked list, you can add and
remove a node at the back of the list with the
same O(1) efficiency.
241-423 ADSA: Linked Lists/5
47
7. The (Doubly)
LinkedList Collection
In Ford & Topp's DSA package
241-423 ADSA: Linked Lists/5
48
UML for LinkedList
241-423 ADSA: Linked Lists/5
49
LinkedList Methods
• The LinkedList() constructor creates an
empty list.
• The toString() method returns a string
representing the list as a comma-separated
sequence of elements enclosed in brackets.
241-423 ADSA: Linked Lists/5
continued
50
• Reuse the Collection methods:
– isEmpty(), size(), contains(), toArray()
• add() inserts a new element at the back of the
list and returns true.
• remove() with an Object reference deletes the
first occurrence of the object in the list
– the method returns true or false depending on
whether a match was found
241-423 ADSA: Linked Lists/5
51
LinkedList Examples
LinkedList<String> aList = new LinkedList<String>();
alist.add("Red");
alist.add("Green");
alist.add("Blue);
System.out.println("Size = " + aList.size());
System.out.println("List contains the string 'White' is " +
aList.contains("White");
Size = 3
List contains the string 'White' is false
241-423 ADSA: Linked Lists/5
52
aList.add("Black");
aList.add("Blue");
// add Black at the end
// add Blue at the end
aList.remove("Blue");
// delete first "Blue"
System.out.println(aList);
// uses toString()
[Red, Green, Black, Blue]
241-423 ADSA: Linked Lists/5
53
LinkedList Index Methods
• The LinkedList can access and update an
element with get() and set(), and modify the
list with the add() and remove().
• The index methods have O(n) worst case
running time. Use these methods only for
small data sets.
241-423 ADSA: Linked Lists/5
54
Example
// create list containing [5,7,9,4,3]
Integer i= list.get(1); // i has value 7
list.remove(1);
241-423 ADSA: Linked Lists/5
// remove value at position 1
continued
55
list.set(2, 8);
// store node 8 at position 2
list.add(2, 6);
// store value 6 at position 2
241-423 ADSA: Linked Lists/5
56
Accessing the Ends of a LinkedList
• Methods for the front of the list:
– getFirst(), addFirst(), removeFirst()
• For the back of the list:
– getLast(), addLast(), removeLast()
• They all are O(1) operations
241-423 ADSA: Linked Lists/5
57
End-of-List Examples
LinkedList<String> list = new LinkedList<String>();
list.addFirst("Tom");
list.addFirst("Debbie");
list.addLast("David");
ist.addLast("Maria");
241-423 ADSA: Linked Lists/5
continued
58
// identify the elements at the ends of the list
System.out.println("First element is " + list.getFirst());
System.out.println("Last element is " + list.getLast());
First element is Debbie
Last element is Maria
241-423 ADSA: Linked Lists/5
continued
59
// Exchange the first and last elements in the list.
// remove elements at the ends of the list
String firstElem = aList.removeFirst();
String lastElem = aList.removeLast();
// add elements back in switched positions
aList.addLast(firstElem);
aList.addFirst(lastElem);
241-423 ADSA: Linked Lists/5
continued
60
// Output elements in the list by position.
// Repeatedly delete first element and display its
// value until list is empty
while (!aList.isEmpty())
System.out.print(aList.removeFirst() + "
Maria
Tom
241-423 ADSA: Linked Lists/5
David
");
Debbie
61
Linked List as a Queue
• A linked list is a natural way to implement a
queue.
– the element at the front of the queue can be
removed with getFirst()
– a new element can be added to the back of the
queue by using addLast()
241-423 ADSA: Linked Lists/5
62
8. Palindromes
• A palindrome is a string that reads
the same forward and backward:
– e.g. "level", "noon.", "Stack Cats"
– ignore non-letters and let capitals == lowercase
• isPalindrome() takes a LinkedList object as an
argument and returns true if the sequence is a
palindrome; false otherwise.
241-423 ADSA: Linked Lists/5
continued
63
Panic in a Titanic, I nap.
Yawn a more Roman way.
A Toyota's a Toyota
Race car
241-423 ADSA: Linked Lists/5
64
public static boolean isPalindrome(LinkedList<?> aList)
{
// list must have 2 or more elements
while (aList.size() > 1) {
// compare elements on opposite ends of list
if ( !aList.getFirst().equals(aList.getLast()) )
return false;
// delete the matching elements
aList.removeFirst();
aList.removeLast();
}
// if we get here then list is a palindrome
return true;
}
241-423 ADSA: Linked Lists/5
65
The "?" Wildcard
• isPalindrome() does not refer to the generic
type of the list. In this case, we may use:
LinkedList<?> aList
• "?" means that we don't care about the type
of the elements of the list.
241-423 ADSA: Linked Lists/5
66
Checking for a Palindrome
import java.util.Scanner;
import ds.util.LinkedList;
public class CheckPali
{
public static void main(String[] args)
{
LinkedList<Character> charList =
new LinkedList<Character>();
// get input line from user
System.out.print("Enter a string: ");
Scanner keyIn = new Scanner(System.in);
String str = keyIn.nextLine();
:
241-423 ADSA: Linked Lists/5
67
// put all letters into list as lowercase chars
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
if (Character.isLetter(ch))
charList.addLast( Character.toLowerCase(ch) );
}
}
if (isPalindrome(charList))
System.out.println("'" + str + "' is a palindrome");
else
System.out.println("'" + str +
"' is not a palindrome");
// end of main()
// isPalindrome() method goes here
} // end of CheckPali class
241-423 ADSA: Linked Lists/5
68
Execution
241-423 ADSA: Linked Lists/5
69
Download