Doubly Linked Lists Doubly Linked Lists: Introduction. Doubly Linked Lists: Implementation Doubly Linked Lists: Analysis Doubly Linked Lists: Creation and destruction Doubly Linked Lists: Accessor methods Doubly Linked Lists: Mutator Methods
Introduction Doubly linked lists are an extension singly linked lists We know that deleting the head element of the singly linked list is easy. It has a constant complexity of 0(1) However, deleting the last element (tail) of a singly linked list has a linear complexity of 0(n). As an alternative implementation, we shall consider in this session the doubly linked list. Each node in a doubly linked list has a link to its successor and predecessor in the same time
Introduction (cont’d) We show below some implementation of these lists Circular Doubly linked Lists dlist head tail a) dlist head b) sentinel dlist head c)
Introduction (cont’d) We show below some empty doubly lists. Doubly linked lists require more memory space than singly linked lists. Doubly linked lists are useful in many applications. Head tail Head sentinel
Doubly Linked Lists: Implementation The java class Doubly Linked Lists defines the proposed implementation of Doubly linked lists. COE Ali Juma’ah Student EE Saleh Fouad Student dlist head tail ICS Saleh Fouad Student NODE1
Implementation (cont’d) The code fragment below shows the design of the list node as defined in the Doubly Linked Lists. 1 public class DoublyLinkedList { 2 protected Element head; 3 protected Element tail; 4 public final class Element { 5 Object datum; 6 Element next; 7 Element previous; 7 Element(Object datum, Element next, Element previous){ 8 this.datum = datum; 9 this.next = next; 10 this.previous = previous; 11 public Object getDatum() \{ 12 return datum; 13 } // End of getDatum() method 14 public Element getNext() \{ 15 return next; 16 } // End of getNext() method 17 public Element getPrevious() \{ 18 return previous; 19 } // End of getPrevious() method 20 } // End of inner class Element 21 } // End of class DoublyLinkedList
Doubly Linked Lists: Space Analysis Now we can take a look at the space requirements of the doublu linked lists: S(n) = sizeof(DoublyLinkedList) + n sizeof(DoublyLinkedList.Element) = 2 sizeof(DoublyLinkedList.Element ref) + n [sizeof(Object ref) + 2 sizeof(DoublyLinkedList.Element ref)] = (2n + 2) sizeof(DoublyLinkedList.Element ref) + n sizeof(Object ref) ExplanationRequired space The list reference has two fields: head (type: Element) and tail (type: Element) = 2 sizeof(DoublyLinkedList.Element ref) sizeof(DoublyLinkedList) The list has n elements of type Element. Each element has three fields-- previous (type Element), datum (type Object), and next (type Element) n sizeof(DoublyLinkedList. Element)
Doubly Linked Lists: Complexity Analysis The constructor of the class Element performs 3 Operations. It has then a complexity of 0(1). To access the class fields, each of the three methods getPrevious(), getDatum(), and getNext() perform 1 operation,. In this case, each of the above methods has a constant complexity of 0(1). Note that the constructor of Doubly LinkedList has an empty implementation. Regardless of this, its running time is clearly constant, i.e., 0(1).
Doubly Linked Lists: Creation & Destruction The following code fragment creates a new doubly linked lists: DoublyLinkedList dlist = DoublyLinkedList(); Destroying (or purging) an existing list is quite easy! 1 public void purge() { 2 head = null; 3 tail = null; 4}//End of method purge() tail Head dlist head tail 3 11 tail Head dlist 3 11 Garbage! It easy to assume that the running time of the method purge() is O(1).
Accsseor Methods The DoublyLinkedList class accsseor methods are shown below: 1 public Element getHead() { 2 return head; 3 } // End of getHead() method 4 public Element getTail() { 5 return tail; 6 } // End of getTail() method 7 public boolean isEmpty() { 8 return head == null; 9 } // End of isEmpty() method 10 public Object getFirst() throws ListEmptyException { 11 if(head == null) 12 throw new ListEmptyException(); 13 return head.datum; 14 } // End of getFirst() method 15 public Object getLast() throws ListEmptyException { 16 if(head == null) 17 throw new ListEmptyException(); 18 return tail.datum; 19 } // End of getLast() method Each on of these method perform 1 opertion each of complexity O(1)!
Mutator Methods The DoublyLinkedList class mutator methods are shown below: 1 public void prepend(Object item) { 2 Element tmp = new Element(item, head, null); 3 if(head != null) { 4 tmp.next.previous = tmp; 5 head = tmp; 6 } 7 else 8 head = tail = tmp; 9 } // End of prepend() method 10 public void append(Object item) { 11 Element tmp = new Element(item, null, tail); 12 if(head != null) { 13 tail.next = tmp; 14 tail = tmp; 15 } // End of if block 16 else 17 head = tail = tmp; 18 } // End of append() method 19 public void assign(DoublyLinkedList dlist) { 20 if(dlist != this) { 21 purge(); 22 for(Element ptr = dlist.head; ptr != null; ptr = ptr.next) 23 append(ptr.datum); 24 } // End of the if block 25 } // End of assign() method complexityMethod Name O(1)prepend() O(1)append() O(n)assign()
Drill Questions Extend the extract() method of MyLInkedlist to work with the DoublyLinkedList. Define your own implementation for the mutator methods of the class DoublyLinkedList.Element. Define an accept() method for the DoublyLinkedList class.