Struktur Data & Algoritme (
Data Structures & Algorithms)
Denny ([email protected]) Suryana Setiawan ([email protected])
Fakultas Ilmu Komputer Universitas Indonesia Semester Genap - 2004/2005
Version 2.0 - Internal Use Only
Linked-List
SDA/LL/V2.0/2
Objectives
dapat memahami pentingnya penggunaan struktur data yang tepat dalam program
dapat memahami cara kerja Linked-List dan analisa kompleksitas waktu insert, delete dan akses
dapat membuat/implementasi Linked-List
SDA/LL/V2.0/3
Outline
Importance and properties of Data Structure
Basics of Linked Lists vs. Array
Linked Lists and Iterators
Linked Lists variant:
Doubly Linked Lists
Circular Linked Lists
Sorted Linked Lists
SDA/LL/V2.0/4
Data Structure
Algorithms require the use of a proper representation of data to achieve efficiency
Data structure (aka ADT – Abstract Data Type) = representation + operations
operation allowed may vary between data structure
• insert
• delete
• access
• update
Kita perlu menganalisa waktu yang dibutuhkan untuk setiap operasi tersebut.
SDA/LL/V2.0/5
Mengapa Butuh Struktur Data
Struktur data membantu tercapainya Component Reusability.
Menerapkan konsep OO paradigm: encapsulation, information- hiding dan abstraction.
SDA/LL/V2.0/6
Macam Struktur Data yang Umum
linked lists
stacks
queues
trees
binary search trees
AVL trees
B-Trees
Trie
hash tables
priority queues
SDA/LL/V2.0/7
ListNode
Linked Lists
Stores a collection of items non-contiguously.
Each item in the list is stored with an indication of where the next item is.
Must know where first item is.
The list will be a chain of objects of type ListNode that contain the data and a reference to the next ListNodein the list.
Allows addition or deletion of items in the middle of collection with only a constant amount of data movement. Contrast this with array.
A0 A1 A2 A3
first last SDA/LL/V2.0/8
ListNode: Definition
public class ListNode {
Object element; // some element ListNode next;
// constructors
ListNode (Object theElement, ListNode n) {
element = theElement;
next = n;
}
ListNode (Object theElement) {
this (theElement, null);
}
ListNode () {
this (null, null);
} }
SDA/LL/V2.0/9
Linked List: Insertion
Insert X immediately after current position
a b c d
current
a b
current x
c d
SDA/LL/V2.0/10
Insertion’s Steps
Insertion immediately after current position // create a new node
tmp = new ListNode( );
// place x in the element field tmp.element = x;
// x’s next node is b tmp.next = current.next;
// a’s next node is x current.next = tmp;
a b
current x
SDA/LL/V2.0/11
Insertion’s Steps
a b
current x
Insertion immediately after current position // create a new node
tmp = new ListNode( );
// place x in the element field tmp.element = x;
// x’s next node is b tmp.next = current.next;
// a’s next node is x current.next = tmp;
SDA/LL/V2.0/12
Simplification of insertion’s code
More efficient approach
tmp = new ListNode (x, current.next);
current.next = tmp;
a b
current x
a b
current x
SDA/LL/V2.0/13
Simplification of insertion’s code
Most efficient approach
current.next = new ListNode (x, current.next);
SDA/LL/V2.0/14
Linked List: append
Insert X immediately at the end of the list
// last refers to the last node in the linked list last.next = new ListNode();
last = last.next; // adjust last
last.element = x; // place x in the node last.next = null; // adjust next
Most efficient approach
last = last.next = new ListNode (x, null);
a b c d
last
a b c X
last d
SDA/LL/V2.0/15
Linked Lists: Basic Deletion
Delete an item immediately after current position
Basic deletion is a bypass in the linked list.
a x b
current
a b
current
SDA/LL/V2.0/16
Deletion’s Steps
Need a reference to node prior to the one to be deleted.
current.next = current.next.next;
a x b
current
a x b
current
a b
current
SDA/LL/V2.0/17
Important Note
Ingat!!! Yang disimpan dalamListNodeadalah reference dari object-nya, BUKAN object-nya itu sendiri atau salinan dari object-nya
SDA/LL/V2.0/18
Iterate the Linked List
Jika item disimpan dalam contiguous array:
//step through array a, outputting each item for (int index = 0; index < a.length; index++)
System.out.println (a[index]);
Jika item disimpan dalam sebuah linked list:
// step through List theList, outputting each item for (ListNode p = theList.first; p != null;
p = p.next) {
System.out.println (p.data);
}
A0 A1 A2 A3
first last
SDA/LL/V2.0/19
Header Nodes
Deletion of first item and insertion of new first item are special cases.
Can be avoided by using header node;
contains no data, but serves to ensure that first "real"
node in linked has a predecessor.
Go to the first element = current set to header.next;
Empty list if header.next == null;
Searching routines will skip header.
A B C
Header
SDA/LL/V2.0/20
Linked Lists: List interface
public interface List {
/**
Test if the list is logically empty.
@return true if empty, false otherwise.
*/
boolean isEmpty ();
/**
Make the list logically empty.
*/
void makeEmpty ();
}
SDA/LL/V2.0/21
Linked Lists: List implementation
public class LinkedList implements List {
// friendly data, so LinkedListItr can have access ListNode header;
/**
Construct the list
*/
public LinkedList () {
header = new ListNode (null);
} /**
Test if the list is logically empty.
@return true if empty, false otherwise.
*/
public boolean isEmpty( ) {
return header.next == null;
}
SDA/LL/V2.0/22
Linked Lists: List implementation
/**
Make the list logically empty.
*/
public void makeEmpty( ) {
header.next = null;
} }
SDA/LL/V2.0/23
Iterator Class
Maintains notion of the current position (aka cursor).
List class provides method that do not depend on any position (such as isEmpty, and makeEmpty).
List iterator (ListItr) provides most other methods such as advance, retrieve, first, which act on the current position stored in the iterator.
SDA/LL/V2.0/24
Iterator Class
// Insert x after current position void insert (x);
// Remove x void remove (x);
// Remove item after current position void removeNext( );
// Set current position to view x boolean find( x );
// Set current position to prior to first void zeroth ();
// Set current position to first void first( );
// Set current to the next node void advance ();
// True if at valid position in list boolean isInList ();
// Return item in current position Object retrieve()
Exceptions thrown for illegal access, insert, or remove.
SDA/LL/V2.0/25
Example
A static member function that computes the number of elements in any list:
public static int listSize (List theList) {
int size = 0;
ListItr itr = new ListItr (theList);
for (itr.first(); itr.isInList(); itr.advance()) {
size++;
}
return size;
}
SDA/LL/V2.0/26
Java Implementations
Mostly straightforward; all routines are short.
ListItrmaintains a reference to the list that it is bound to as a private data member.
Because ListItris in the same package as List, if List's data is friendly, it can be accessed by ListItr.
SDA/LL/V2.0/27
LinkedListItr implementation
public class LinkedListItr implements ListItr /** contains List header. */
protected LinkedList theList;
/** stores current position. */
protected ListNode current;
/**
Construct the list.
As a result of the construction, the current position is the first item, unless the list is empty, in which case the current position is the zeroth item.
@param anyList a LinkedList object to which this iterator is permanently bound.
*/
public LinkedListItr( LinkedList anyList ) {
theList = anyList;
current = theList.isEmpty( ) ? theList.header : theList.header.next;
}
SDA/LL/V2.0/28
/**
Construct the list.
@param anyList a LinkedList object to which this iterator is permanently bound. This constructor is provided for convenience. If anyList is not a LinkedList object, a ClassCastException will result.
*/
public LinkedListItr( List anyList ) throws ClassCastException {
this( ( LinkedList ) anyList );
} /**
* Advance the current position to the next node in the list.
* If the current position is null, then do nothing.
* No exceptions are thrown by this routine because in the
* most common use (inside a for loop), this would require the
* programmer to add an unnecessary try/catch block.
*/
public void advance( ) {
if( current != null ) current = current.next;
}
SDA/LL/V2.0/29
/**
* Return the item stored in the current position.
* @return the stored item or null if the current position
* is not in the list.
*/
public Object retrieve( ) {
return isInList( ) ? current.element : null;
} /**
* Set the current position to the header node.
*/
public void zeroth( ) {
current = theList.header;
} /**
* Set the current position to the first node in the list.
* This operation is valid for empty lists.
*/
public void first( ) {
current = theList.header.next;
}
SDA/LL/V2.0/30
/**
* Insert after the current position.
* current is set to the inserted node on success.
* @param x the item to insert.
* @exception ItemNotFound if the current position is null.
*/
public void insert( Object x ) throws ItemNotFound {
if( current == null )
throw new ItemNotFound( "Insertion error" );
ListNode newNode = new ListNode( x, current.next );
current = current.next = newNode;
}
SDA/LL/V2.0/31
/**
* Set the current position to the first node containing an item.
* current is unchanged if x is not found.
* @param x the item to search for.
* @return true if the item is found, false otherwise.
*/
public boolean find( Object x ) {
ListNode itr = theList.header.next;
while( itr != null && !itr.element.equals( x ) ) itr = itr.next;
if( itr == null ) return false;
current = itr;
return true;
}
SDA/LL/V2.0/32
/**
* Remove the first occurrence of an item.
* current is set to the first node on success;
* remains unchanged otherwise.
* @param x the item to remove.
* @exception ItemNotFound if the item is not found.
*/
public void remove( Object x ) throws ItemNotFound {
ListNode itr = theList.header;
while( itr.next != null && !itr.next.element.equals( x ) ) itr = itr.next;
if( itr.next == null )
throw new ItemNotFound( "Remove fails" );
itr.next = itr.next.next; // Bypass deleted node current = theList.header; // Reset current }
SDA/LL/V2.0/33
/**
* Remove the item after the current position.
* current is unchanged.
* @return true if successful false otherwise.
*/
public boolean removeNext( ) {
if( current == null || current.next == null ) return false;
current.next = current.next.next;
return true;
} /**
* Test if the current position references a valid list item.
* @return true if the current position is not null and is
* not referencing the header node.
*/
public boolean isInList( ) {
return current != null && current != theList.header;
}
SDA/LL/V2.0/34
Note on Exceptions
Some routines throw ItemNotFoundexceptions.
However, do not overuse exceptions, because they must always be caught or propagated. As an
example, advancedoes not throw an exception, even if we have already advanced past the end. Otherwise, listSizewould need a try/catch block.
SDA/LL/V2.0/35
Linked List Properties
Running Time Analysis
insert next, prepend - O(1)
delete next, delete first - O(1)
find - O(n)
retrieve current position - O(1)
Advantages
Growable (compared to array)
Cepat mengakses/insert/delete elemen terdepan dan terbelakang (jika menyimpan juga posisi terbelakang)
Disadvantages
Sering memanggil operator new(compare to array)
overhead one reference for each node
SDA/LL/V2.0/36
Cetak Isi Linked List
Cara 1: Tanpa Iterator, Iteratif public class LinkedList { public void print () {
// step through list, outputting each item ListNode p = header.next;
while (p != null) {
System.out.println (p.data);
p = p.next;
} }
SDA/LL/V2.0/37
Cetak Isi Linked List (2)
Cara 2: Tanpa Iterator, Rekursif public class LinkedList { ...
private static void printRec (ListNode node) {
if (node != null) {
System.out.println (node.data);
printRec (node.next);
} }
public void print () {
printRec (header.next);
} }
SDA/LL/V2.0/38
Cetak Isi Linked List (3)
Cara 3: “rekursif”
class ListNode {
...
public void print () {
System.out.println (data);
if (next != null) { next.print ();
} }
} // end of class ListNode class LinkedList
{
public void print () {
if (header.next != null) { header.next.print ();
} } }
SDA/LL/V2.0/39
Cetak Isi Linked List (4)
Cara 4: menggunakan iterator
class LinkedList {
...
public void print (List theList) {
ListItr itr = new ListItr (theList);
for (itr.first(); itr.isInList();
itr.advance()) {
System.out.println (itr.retrieve ());
} } }
SDA/LL/V2.0/40
Sorted Linked Lists
Maintains items in sorted order.
Almost all operations are same as linked lists, except for insert.
In fact, a sorted linked list IS-A linked list, suggesting that inheritance may be used. Extend a SortListItr from ListItr.
However, items in a sorted linked list should be Comparable.
SDA/LL/V2.0/41
Simple Implementation
Use inheritance, and create Insertmethod public void insert( Comparable X )
Note however, that in this implementation, we have no assurance that the list is sorted, because it can be accessed by either a SortListItror a ListItr.
See the textbook for details.
SDA/LL/V2.0/42
Important Note
ListItrused the equalsmember function in find and remove.
Must make sure MyIntegerhas an equalsmember function if we are storing a linked list of MyIntegers.
Signature MUST BE
public boolean equals( Object Rhs )
The following signature is wrong!
public boolean equals( Comparable Rhs )
If you try it, the method from class Objectwill be inherited and used:
public boolean equals (Object obj) {
return (this == obj);
}
SDA/LL/V2.0/43
Other Linked Lists
Doubly-linked lists: Each list node stores both the previous and next nodes in the list. Useful for traversing linked lists in both directions.
Circular-linked lists: Last node's next references the first node. Works with or without headers.
A
head tail
prev
next
A B C
first
prev
next
SDA/LL/V2.0/44
Doubly-linked lists: Wrong InsertNext
newNode = new DoublyLinkedListNode ( x );
1 newNode.prev = current;
2 newNode.prev.next = newNode;
…
…
x a b
1 2
SDA/LL/V2.0/45
Doubly-linked lists: insertNext
1 newNode = new DoublyLinkedListNode (x);
2 newNode.prev = current;
3 newNode.next = current.next;
4 newNode.prev.next = newNode;
5 newNode.next.prev = newNode;
6 current = newNode;
A B
current
X prev
next newNode
1 3
2 5
4
6
SDA/LL/V2.0/46
Doubly-linked lists: DeleteCurrent
1. current.prev.next = current.next;
2. current.next.prev = current.prev;
3. current = current.prev;
x
b a
current 1 2 3
SDA/LL/V2.0/47
JDK: package java.util
Collection - List - LinkedList
Iterator - ListIterator
SDA/LL/V2.0/48
Summary
ListNode
List, LinkedList
Iterator class
a class that maintains a current position and performs all routines that depend on knowing the position in the list.
Advantage & Disadvantage of linked list
Growable
Overhead a pointer, new operator
Sequential access only
SDA/LL/V2.0/49
Further Reading
Cari dan pelajari struktur data yang telah tersedia di Java API
http://telaga.cs.ui.ac.id/WebKuliah/java5/
docs/api/java/util/package-summary.html
Generics in Java 2 SE 5:
http://telaga.cs.ui.ac.id/WebKuliah/java5/
Java5-Generics.pdf
Chapter 6 & 16
SDA/LL/V2.0/50
What’s Next
Stacks & Queues - Chapter 6, 15, 11