Doubly-Linked Lists Cmput Lecture 16 Department of Computing Science University of Alberta ©Duane Szafron 2000 Some code in this lecture is based on code from the book: Java Structures by Duane A. Bailey or the companion structure package Revised 2/24/00
©Duane Szafron About This Lecture In this lecture we will learn about an implementation of the List Interface called Doubly-Linked List.
©Duane Szafron Outline Drawing Doubly Linked Lists DoublyLinkedListElement class DoublyLinkedList class
©Duane Szafron Doubly-Linked List Diagrams A doubly-linked list node has two links, one forward and one backward. doubly-linked list The doubly-linked list has references to its head and tail nodes. This symmetry makes the implementation simpler. “Fred”“Wilma”“Barney”3
©Duane Szafron Constructing a Node When a DoublyLinkedListElement (node) is constructed, four links may need to be set. “Fred” “Wilma” “Barney” If one or both of the “neighboring” nodes is null then fewer links must be set. “Wilma” “Barney” null
©Duane Szafron DoublyLinkedListElement 1 public class DoublyLinkedListElement { protected Object data; protected DoublyLinkedListElement next; protected DoublyLinkedListElement previous; public DoublyLinkedListElement (Object element, DoublyLinkedListElement nextNode, DoublyLinkedListElement previousNode) { //post: initializes the node to contain the given // object and link to the given next and previous nodes. this.data = element; this.next = nextNode; this.previous = previousNode; code based on Bailey pg. 118 element previousNodenextNode
©Duane Szafron DoublyLinkedListElement 2 public DoublyLinkedListElement (Object element) { //post: initializes the receiver node to be the // only node in a list. this(element, null, null); } code based on Bailey pg. 118 if (nextNode != null) nextNode.previous = this; if (previousNode != null) previousNode.next = this; }
©Duane Szafron DoublyLinkedList - State & Constructor public class DoublyLinkedList implements List { protected int count; protected DoublyLinkedListElement head; protected DoublyLinkedListElement tail; public DoublyLinkedList() { //post: initializes the list to be empty. this.head = null; this.tail = null; this.count = 0; } code based on Bailey pg. 119
©Duane Szafron DoublyLinkedList - Store Interface /* Interface Store Methods */ public int size() { //post: returns the number of elements in the list. return this.count; } public boolean isEmpty() { // post: returns the true iff store is empty. return this.size() == 0 } public void clear() { // post: clears the list so that it contains no elements. this.head = null; this.tail = null; this.count = 0; } code based on Bailey pg. 108
©Duane Szafron DoublyLinkedList - Collection Interface 1 /* Interface Collection Methods */ public boolean contains (Object anObject); // pre: anObject is non-null // post: returns true iff the collection contains the object DoublyLinkedListElement cursor; cursor = this.head; // partial traversal while ((cursor != null) && (!cursor.value().equals(anObject)) cursor = cursor.next(); return cursor != null; } code based on Bailey pg. 114
©Duane Szafron DoublyLinkedList Collection Interface 2 public void add (Object anObject) { // pre: anObject is non-null // post: the object is added to the collection. The // replacement policy is not specified this.addToHead(anObject); } public Object remove (Object anObject); // pre: anObject is non-null // post: removes object “equal” to anObject and returns it, // otherwise returns nil // Read the textbook after understanding this lecture. } public Iterator elements() { // post: return an iterator for traversing the collection // Ignore this one until textbook Chapter 8! } code based on Bailey pg. 108
©Duane Szafron head “Fred”“Wilma”“Barney” 3 DoublyLinkedList - addToHead() vers 1 /* Interface List Methods */ public void addToHead(Object anObject) { // pre: anObject is non-null // post: the object is added to the beginning of the list this.head = new DoublyLinkedListElement(anObject, this.head, null); this.count++; } code based on Bailey pg. 119 “Pebbles”
©Duane Szafron DoublyLinkedList - addToHead() problem /* Interface List Methods */ public void addToHead (Object anObject) { // pre: anObject is non-null // post: the object is added to the beginning of the list this.head = newDoublyLinkedListElement(anObject, this.head, null); this.count++; } code based on Bailey pg Check the boundaries! If the list is empty, the list tail must be bound to the new node. 0 1 “Pebbles” 3 12
©Duane Szafron DoublyLinkedList - addToHead() /* Interface List Methods */ public void addToHead (Object anObject) { // pre: anObject is non-null // post: the object is added to the beginning of the list this.head = new DoublyLinkedListElement(anObject, this.head, null); // fix tail, if necessary if (this.tail == null) this.tail = this.head; this.count++; } code based on Bailey pg. 119
©Duane Szafron DoublyLinkedList - removeFromHead() vers 1 public Object removeFromHead() { // pre: list is not empty // post: removes and returns first object from the list DoublyLinkedListElement temp; temp = this.head; this.head = this.head.next(); if (this.head != null) this.head.previous = null; this.count--; return temp.value(); } code based on Bailey pg “Fred”“Wilma”“Barney”3 4 temp 4 3
©Duane Szafron DoublyLinkedList - removeFromHead() problem public Object removeFromHead() { // pre: list is not empty // post: removes and returns first object from the list DoublyLinkedListElement temp; temp = this.head; this.head = this.head.next(); if (this.head != null) this.head.previous = null; this.count--; return temp.value(); } code based on Bailey pg “Fred” temp 4 Check the boundaries! If the list has one node, the list tail must be bound to null. 3
©Duane Szafron DoublyLinkedList - removeFromHead() public Object removeFromHead() { // pre: list is not empty // post: removes and returns first object from the list DoublyLinkedListElement temp; temp = this.head; this.head = this.head.next(); if (this.head != null) this.head.previous = null; else // clean up tail if list is now empty this.tail = null; this.count--; return temp.value(); } code based on Bailey pg. 110
©Duane Szafron DoublyLinkedList - peek() and tailPeek() public Object peek () { // pre: list is not empty // post: returns the first object in the list without // modifying the list return this.head.value(); } public Object tailPeek () { // pre: list is not empty // post: returns the last object in the list without // modifying the list return this.tail.value(); } code based on Bailey pg. 111
©Duane Szafron DoublyLinkedList - addToTail() public void addToTail (Object anObject) { // pre: anObject is non-null // post: the object is added at the end of the list this.tail = new DoublyLinkedListElement(anObject, null, this.tail); if (this.head == null) this.head = this.tail; this.count++; } code based on Bailey pg “Fred”“Wilma”“Barney” 3 4“Pebbles” Look at the symmetry with addToHead()! Check the boundaries! If the list was empty, bind the head to the new node. 1
©Duane Szafron DoublyLinkedList - removeFromTail() public Object removeFromTail() { // pre: list is not empty // post: the last object in the list is removed and returned DoublyLinkedListElement temp; Assert.pre(!this.isEmpty(), “List is not empty”); temp = this.tail; this.tail = this.tail.previous(); if (this.tail == null) this.head = null; else //must set next for the previously last node this.tail.setNext(null); this.count--; return temp.value(); } code based on Bailey pg. 119 Just copy from removeFromHead() based on symmetry!
©Duane Szafron Some Principles from the Textbook 12. Question asymmetry principles from Bailey ch. 6