380 likes | 640 Views
Linked Lists. Chapter 4. Linked List : Definition. Linked List: A collection of data items of the same type that are stored in separate objects referred to as "nodes".
E N D
Linked Lists Chapter 4
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.
null 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
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.
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
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
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
To instantiate a Node containing an Integer: Node n = new Node(new Integer(6)); or containing a character: Node n = new Node(new Character('A')); 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; } // end getNext } // end class Node
newNode Inserting a Node into a Linked List newNode = new Node ( Integer (5) ); newNode.setNext ( cur ); prev.setNext ( newNode ); prev cur head 1 3 7 9 5
newNode 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 5
Deleting a Node from a Linked List prev.setNext ( cur.getNext() ); prev cur head 1 3 7 9
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
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
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) { // ifbecomeswhile // 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
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
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?
Criteria for Linked Lists - ACIDS • Decide which General List implementation is better by observing General List operations: • ACIDStests how easily are operations done • Add • Change • Inspect • Delete • Sort
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.
ACIDS Criteria • Arrays are better for sorting or finding items. • Allow random access to elements. • This allows the use of divide and conquer algorithms.
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
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
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
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
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
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 Node newNode = new Node(item, head); head = newNode; } else { 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
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
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
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()); } }
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
Iterative reversed listingWhy 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()+" "); } } }
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
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
Doubly Linked List Implementation (2) • Assume: • add set and get methods for prev reference to the Node class. • possibly change the insertion and deletion methods in the List class.
X Doubly Linked List Insertion // inserting AFTER cur tmp = new Node(Character('X'), cur.next, cur); cur.next.prev = tmp; cur.next = tmp; cur A M Z tmp
Doubly Linked List Deletion // deleting cur cur.Next.Prev = cur.Prev; cur.Prev.Next = cur.Next; cur = null; A M Z cur
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.
Circular Linked Lists • 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 A B C D Head
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 ); }