Linked Lists Chapter 4 1
Linked List : Definition Linked List: A collection of data items of the same type that are stored in separate objects referred to as "nodes". Each node contains, in addition to its data value(s) a reference to an object of the same type. This reference is used to connect one node to the next node in the list. 2
Linked List : Definition Linked List: An external reference usually referred to as the "head" of the list contains the address of the first node object. Diagram of a sample linked list containing character data: head A B C D null 3
A Linked List Node Class First attempt at a class for a linked list of integers: public class IntegerNode { public int item; public IntegerNode next; } The problem with this solution is that it uses no data hiding - all data fields in a class should be "private" and data should be set/retrieved only with constructors, accessors, and mutators. 4
Final IntegerNode Class public class IntegerNode { private int item; private IntegerNode next; public IntegerNode(int newitem) { item = newitem; next = null; } // end constructor public IntegerNode(int newitem, IntegerNode nextnode) { item = newitem; next = nextnode; } // end constructor 5
Final IntegerNode Class (2) public void setitem(int newitem) { item = newitem; } // end setitem public int getitem() { return item; } // end getitem public void setnext(integernode nextnode) { next = nextnode; } // end setnext public IntegerNode getnext() { return next; } // end getnext } // end class IntegerNode 6
A Polymorphic Linked List Node public class Node { private Object item; private Node next; public Node(Object newitem) { item = newitem; next = null; } // end constructor public Node(Object newitem, Node nextnode) { item = newitem; next = nextnode; } // end constructor 7
A Polymorphic Linked List Node public void setitem(object newitem) { item = newitem; } // end setitem public Object getitem() { return item; } // end getitem public void setnext(node nextnode) { next = nextnode; } // end setnext public Node getnext() { return next; To instantiate a Node containing an Integer: } // end getnext } // end class Node Node n = new Node(new Integer(6)); or containing a character: Node n = new Node(new Character('A')); 8
Inserting a Node into a Linked List newnode = new Node ( Integer (5) ); newnode.setnext ( cur ); prev.setnext ( newnode ); prev cur head 1 newnode 3 7 9 5 9
Inserting a Node into a Linked List (First Node) newnode = new Node ( Integer (5) ); newnode.setnext ( head ); head = newnode; prev cur head 1 3 7 9 newnode 5 10
Deleting a Node from a Linked List prev.setnext ( cur.getnext() ); prev cur head 1 3 7 9 11
Traversing a Linked List for ( Node cur = head ; cur!= null ; cur = cur.getnext() ) { System.out.println ( cur.getitem() ); } cur head 1 3 7 9 null 12
Recursive Linked List Traversal private static void writelist(node nextnode) { // ------------------------------------------------------- // Writes a list of objects. // Precondition: The linked list is referenced by nextnode. // Postcondition: The list is displayed. The linked list // and nextnode are unchanged. // ------------------------------------------------------- if (nextnode!= null) { // write the first data object System.out.println(nextNode.getItem()); // write the list minus its first node writelist(nextnode.getnext()); } // end if } // end writelist 13
Removing Tail Recursion private static void writelist(node nextnode) { // ------------------------------------------------------- // Writes a list of objects. // Precondition: The linked list is referenced by nextnode. // Postcondition: The list is displayed. The linked list // and nextnode are unchanged. // ------------------------------------------------------- // nextnode holds the head of the list on entry while (nextnode!= null) { // if becomes while // write the data object referenced by nextnode System.out.println(nextNode.getItem()); // replace recursive call with parameter update nextnode = nextnode.getnext(); } // end while } // end writelist 14
Insert and Delete operations on an empty list Problem with insertion and deletion methods: They require special cases and different actions for first nodes. The addition of a dummy head node to the linked list eliminates the special cases -the node does not contain any data -an empty list consists of head and the dummy node 15
Abstract Data Type List A linked list is actually just one implementation of the higher object which is a General List A General List could be implemented using arrays rather than linked lists How would that implementation change from the linked list implementation? 16
Criteria for Linked Lists - ACIDS Decide which General List implementation is better by observing General List operations: ACIDS tests how easily are operations done Add Change Inspect Delete Sort 17
ACIDS Criteria Linked lists are better for adding or deleting items. Insertion and deletion require constant time complexity once position is located. In array based lists insertion and deletion require linear time complexity since all n items might have to be moved. 18
ACIDS Criteria Arrays are better for sorting or finding items. Allow random access to elements. This allows the use of divide and conquer algorithms. 19
Interface for ADT List // **************************************************** // Interface for the ADT list // **************************************************** public interface ListInterface { // list operations: public boolean isempty(); public int size(); public void addfirst(comparable item); public void addlast(comparable item); public void remove(comparable item); public Node find(comparable item); public void removeall(); } // end ListInterface 20
Comparable Node Class public class Node { private Comparable item; private Node next; public Node(Comparable newitem) { item = newitem; next = null; } // end constructor public Node(Comparable newitem, Node nextnode) { item = newitem; next = nextnode; } // end constructor 21
Comparable Node Class (2) public void setitem(comparable newitem) { item = newitem; } // end setitem public Comparable getitem() { return item; } // end getitem public void setnext(node nextnode) { next = nextnode; } // end setnext public Node getnext() { return next; } // end getnext } // end class Node 22
Implementation of ADT List // **************************************************** // Reference-based implementation of ADT list. // **************************************************** public class List implements ListInterface { // reference to linked list of items private Node head; private int numitems; // number of items in list public List() { numitems = 0; head = null; } // end default constructor public boolean isempty( ) { return numitems == 0; } // end isempty public int size( ) { return numitems; } // end size 23
Implementation of ADT List (2) public Node find(comparable finditem) { // Locates a specified node in a linked list. // Returns a reference to the desired node. Node curr = head; // Note order (if curr == null, do not use curr.getitem) while((curr!= null) && (finditem.compareto(curr.getitem())!= 0)) { curr = curr.getnext(); } // end while return curr; } // end find public void addfirst(comparable item) { // insert a new first node into the list Node newnode = new Node(item, head); head = newnode; numitems++; } // end addfirst 24
Implementation of ADT List (3) public void addlast(comparable item) { // insert a new last node into the list Node curr = head; if (curr == null) { // insert a new first (and only) node } else { } Node newnode = new Node(item, head); head = newnode; while(curr.getnext()!= null) curr = curr.getnext(); // curr now contains a ref to the last node on the list Node newnode = new Node(item); curr.setnext(newnode); numitems++; } // end addlast 25
Implementation of ADT List (4) public void remove(comparable removeitem) { if(isempty()) return; Node curr = head, prev = null; if(curr == null) return; while((curr!=null)&&(removeitem.compareto(curr.getitem())!= 0)) { prev = curr; curr = curr.getnext(); } // end while - if curr == null removeitem was not found if(curr!= null) { // if node is not found do nothing if(curr == head) // remove first node head = head.getnext(); else prev.setnext(curr.getnext()); // remove node after prev numitems--; } } // end remove 26
Implementation of ADT List (5) public void removeall() { // setting head to null causes list to be // unreachable and thus marked for garbage collection head = null; numitems = 0; } // end removeall 27
Implementation of ADT List (6) public void printlist() { // calls the recursive method to print the linked list printnode(head); System.out.println(); } private void printnode(node curr) { // the recursive printing method if(curr!= null){ System.out.print(curr.getItem()+" "); printnode(curr.getnext()); } } 28
Implementation of ADT List (7) public void printreverse() { // calls the recursive method to print reversed printreverse(head); // Signature forces the method below System.out.println(); } // Distinguished from above by its signature (parameter list) private void printreverse(node curr) { // the recursive printing method to list IN REVERSE if(curr!= null){ // Recursively print everything AFTER this node printreverse(curr.getnext()); // before printing this node itself System.out.print(curr.getItem()+" "); } } } // end List 29
Iterative reversed listing Why recursion is your friend //NOTE: this is not in fact part of the implementation private void printreverse(node head) { // the iterative printing method to list IN REVERSE if(head!= null){ int n, // Number of items to skip skip; // Loop for skipping for ( n = this.numitems-1; n >= 0; n-- ) { Node curr = head; for ( skip = 0; skip < n; skip++ ) { curr = curr.getnext(); } System.out.print(curr.getItem()+" "); } } } 30
Doubly Linked Lists Even though each node in a singly linked list has a well defined predecessor it is impossible to move from a node to its predecessor Doubly linked lists solve this problem by allowing movement in both directions through a list Accomplished by adding a pointer to each node which contains the address of the previous node 31
Doubly Linked List Implementation public class Node { private Comparable item; private Node next; private Node prev; public Node(Comparable newitem) { item = newitem; next = null; prev = null; } // end constructor public Node(Comparable newitem, Node nextnode, Node prevnode) { item = newitem; next = nextnode; prev = prevnode; } // end constructor 32
Doubly Linked List Implementation Assume: (2) add set and get methods for prev reference to the Node class. possibly change the insertion and deletion methods in the List class. 33
Doubly Linked List Insertion cur A M Z tmp X // inserting AFTER cur tmp = new Node(Character('X'), cur.next, cur); cur.next.prev = tmp; cur.next = tmp; 34
Doubly Linked List Deletion A M Z // deleting cur cur.next.prev = cur.prev; cur.prev.next = cur.next; cur = null; cur 35
Header Nodes for Doubly Linked Lists Inserting /deleting first and last nodes are special cases for doubly linked lists (with head and tail references) By adding a dummy header node to both ends of the list -a single routine with no conditions can be used to insert into or delete from doubly linked lists. 36
Circular Linked Lists Head A B C D The last node in the list points to first A single node list points to itself Problems can arise when traversing the list to its end - easy to construct an infinite loop 37
Solution: Use Object Inequality Node cur = head; // Bottom-driven loop, so enter only if non-zero passes if ( cur!= null ) { do { System.out.println ( cur.getitem() ); cur = cur.getnext() ) } while ( cur!= head ); } 38