Presentation is loading. Please wait.

Presentation is loading. Please wait.

Linked Lists Linear collections. List Abstract Data Type List interface built-in to the collections framework The built-in List interface is a dynamic.

Similar presentations


Presentation on theme: "Linked Lists Linear collections. List Abstract Data Type List interface built-in to the collections framework The built-in List interface is a dynamic."— Presentation transcript:

1 Linked Lists Linear collections

2 List Abstract Data Type List interface built-in to the collections framework The built-in List interface is a dynamic linear collection that DOES support random access This presentation uses a simplified List interface Our list is NOT the built-in list! Our list does NOT support random access Our list is dynamic (grows/shrinks as needed)

3 Java List Interface (Partial listing) void add(int index, Object element) - Inserts the specified element at the specified position in this list boolean add(Object element) - Appends the specified element to the end of this List. boolean addAll(int index, Collection c) - Inserts all of the elements in the specified collection into this list at the specified position. void clear() – Removes all elements from the list boolean equals(Object element) – Compares the specified object with this list for equality Object get(int index) – Returns the element at the specified index int indexOf(Object element) – Returns the index of the first occurrence of this object in the list boolean isEmpty() – Returns true if this list contains no elements and false otherwise Iterator iterator() – Returns an iterator over the elements of the list int lastIndexOf(Object element) – Returns the index of the last occurrence of element in the list Object remove(int index) – Removes and returns the element at the specified index Object set(int index, Object element) – Replaces the item at the specified index with the specified object int size() – Returns the number of elements in the list

4 Our List Interface Fundamental Methods void addToFront(Object d) Adds object d to the front of the list void addToTail(Object d) Adds object d to the end of the list Object removeFirst() Removes and returns the first element of the list An error occurs if the list is empty Object removeLast() Removes and returns the last element of the list An error occurs if the list is empty Object first() Returns the first element of the list An error occurs if the list is empty Object last() Returns the last element of the list An error occurs if the list is empty interface List{ public void addToFront(Object o); public void addToTail(Object o); public Object removeFirst(); public Object removeLast(); public Object first(); public Object last(); public int size(); public boolean isEmpty(); }

5 List ADT ()errortheList.removeLast() () B theList.removeLast() ( B ) A theList.removeLast() ( B, A ) Y theList.removeLast() ( B, A, Y ) X theList.removeFirst() ( X, B, A, Y ) Y theList.last() ( X, B, A, Y ) X theList.first() ( X, B, A, Y ) X theList.first() ( X, B, A, Y )nonetheList.addToTail( Y ) ( X, B, A )nonetheList.addToFront( X ) ( B, A )nonetheList.addToFront( B ) ( A )nonetheList.addToFront( A ) ListOutputOperation

6 List Implementation Sequential Implementation (using arrays) Use an array to hold data elements Has a fixed capacity with (probably many) wasted slots. Insertion at the beginning of the list is slow (linear or O(n) performance). Keep track of the size of the list explicitly. Identical to a Vector data: size: 5 List Object index 0index 11 Data Objects

7 Java Vector Class Hierarchy Vector AbstractList AbstractCollection Object List Interface Collection Interface

8 Array List Performance MethodRun-time performance void add(int index, Object element) O(n) boolean add(Object element) O(1) void clear() O(1) or O(n) Object get(int index) O(1) int indexOf(Object element) O(n) Object remove(int index) O(n) Object set(int index, Object element) O(1)

9 List Implementation Singly-Linked Implementation: Uses a recursively-defined list node structure to hold data elements Keep track of only the head node and can access all other nodes by following a link to the next node Insertions and removals are done by changing the links. No shifting of data is ever required Next Data Node Object Data Object head List Object Next Data Next Data

10 Singly Linked List class SListNode { private SListNode next; private Object data; SListNode(Object d) { data = d; next = null; } SListNode(Object d, SListNode n) { data = d; next = n; } public SListNode getNext() { return next; } public Object getData() { return data; } public void setNext(SListNode n) { next = n; } public void setData(Object d) { data = d; } Each node is a link in a chain of nodes. Each node can only see forward. Each node contains a data element.

11 Singly Linked List class SinglyLinkedList implements List{ private SListNode head; private int size; SinglyLinkedList() { head = null; size = 0; } public void addToFront(Object o) { … } public void addToTail(Object o) { … } public Object removeFirst() { … } public Object removeLast() { … } } The list keeps track of the first link (called the head ) from which all other links can be accessed. interface List{ public void addToFront(Object o); public void addToTail(Object o); public Object removeFirst(); public Object removeLast(); public Object first(); public Object last(); public int size(); public boolean isEmpty(); }

12 Singly Linked List Insertion head List Object Next Data Next Data Next Data Node Object Data Object Inserting an item means changing links (not shifting data) How do we insert an item at the front of this list?

13 Singly Linked List Insertion head List Object Next Data Next Data Next Data Node Object Data Object public void addToFront(Object o) { head = new SListNode(o, head); size++; } public void addToFront(Object o) { head = new SListNode(o, head); size++; } Show me the code!

14 Singly Linked List Removal head List Object Next Data Next Data Next Data Node Object Data Object Removing an item means changing links (not shifting data) How do we remove an item from the front of this list?

15 Singly Linked List Removal head List Object Next Data Next Data Next Data Node Object Data Object public Object removeFirst() { if(isEmpty()) { throw new NoSuchElementException(); } SListNode node = head; head = head.getNext(); size--; return node.getData(); } public Object removeFirst() { if(isEmpty()) { throw new NoSuchElementException(); } SListNode node = head; head = head.getNext(); size--; return node.getData(); } nullPointerException! Aaargh!!!

16 Singly Linked List Example (lists are entertaining and fun!) public Object removeFirst() { if(isEmpty()) { throw new NoSuchElementException(); } SListNode node = head; head = head.getNext(); size--; return node.getData(); } public Object removeFirst() { if(isEmpty()) { throw new NoSuchElementException(); } SListNode node = head; head = head.getNext(); size--; return node.getData(); } public void addToFront(Object o) { head = new SListNode(o, head); size++; } public void addToFront(Object o) { head = new SListNode(o, head); size++; } List list = new SinglyLinkedList(); for(int i=0; i<3; i++) { list.addToFront(new Integer(i)); } while(!list.isEmpty()) { System.out.println(list.removeFirst()); } List list = new SinglyLinkedList(); for(int i=0; i<3; i++) { list.addToFront(new Integer(i)); } while(!list.isEmpty()) { System.out.println(list.removeFirst()); }

17 Linked List Insertion Next Data Node Object Data Object head List Object Next Data Next Data What needs to happen to insert at the end of this list? Inserting at the end means changing the link of the last node! Since we only know about the first node we have to navigate through the list until the last node is found. We then change its link.

18 Singly Linked List Insertion public void addToTail(Object value) { SListNode newNode = new SListNode(value, null); if(isEmpty()) { head = newNode; } else { SListNode n = head; while(n.getNext() != null) { n = n.getNext(); } n.setNext(newNode); } size++; } public void addToTail(Object value) { SListNode newNode = new SListNode(value, null); if(isEmpty()) { head = newNode; } else { SListNode n = head; while(n.getNext() != null) { n = n.getNext(); } n.setNext(newNode); } size++; } Um, Ah, ?, …, getNext! Inserting at the end means changing the link of the last node! Since we only know about the first node we have to navigate through the list until the last node is found. We then change its link.

19 Singly Linked List Removal public Object removeLast() { if(isEmpty()) { throw new NoSuchElementException(); } SListNode tmp = head, prev = null; while(tmp.getNext() != null) { prev = tmp; tmp = tmp.getNext(); } if(prev == null) { head = null; } else { prev.setNext(null); } size--; return tmp.getData(); } public Object removeLast() { if(isEmpty()) { throw new NoSuchElementException(); } SListNode tmp = head, prev = null; while(tmp.getNext() != null) { prev = tmp; tmp = tmp.getNext(); } if(prev == null) { head = null; } else { prev.setNext(null); } size--; return tmp.getData(); } Removing at the end means changing the link of the second-to-last node! Since we only know about the first node we have to navigate through the list until the second-to-last node is found. We then change its link.

20 Singly Linked List Example (lists are entertaining and fun!) List list = new SinglyLinkedList(); for(int i=0; i<3; i++) { list.addToTail(new Integer(i)); } while(!list.isEmpty()) { System.out.println(list.removeLast()); } List list = new SinglyLinkedList(); for(int i=0; i<3; i++) { list.addToTail(new Integer(i)); } while(!list.isEmpty()) { System.out.println(list.removeLast()); } public void addToTail(Object value) { SListNode newNode = new SListNode(value, null); if(isEmpty()) { head = newNode; } else { SListNode n = head; while(n.getNext() != null) { n = n.getNext(); } n.setNext(newNode); } size++; } public void addToTail(Object value) { SListNode newNode = new SListNode(value, null); if(isEmpty()) { head = newNode; } else { SListNode n = head; while(n.getNext() != null) { n = n.getNext(); } n.setNext(newNode); } size++; }

21 Singly Linked List Example (lists are entertaining and fun!) List list = new SinglyLinkedList(); for(int i=0; i<3; i++) { list.addToTail(new Integer(i)); } while(!list.isEmpty()) { System.out.println(list.removeLast()); } List list = new SinglyLinkedList(); for(int i=0; i<3; i++) { list.addToTail(new Integer(i)); } while(!list.isEmpty()) { System.out.println(list.removeLast()); } public Object removeLast() { if(isEmpty()) { throw new NoSuchElementException(); } SListNode tmp = head, prev = null; while(tmp.getNext() != null) { prev = tmp; tmp = tmp.getNext(); } if(prev == null) { head = null; } else { prev.setNext(null); } size--; return tmp.getData(); } public Object removeLast() { if(isEmpty()) { throw new NoSuchElementException(); } SListNode tmp = head, prev = null; while(tmp.getNext() != null) { prev = tmp; tmp = tmp.getNext(); } if(prev == null) { head = null; } else { prev.setNext(null); } size--; return tmp.getData(); }

22 Singly Linked List Variations There are variations on implementation that make coding somewhat simpler use a sentinel node as the head to simplify the code (doesn t do much for singly-linked lists) sentinel node is always present (even in an empty list) sentinel node stores no data sentinel node serves only as a bookend public SinglyLinkedList implements List { private SListNode head; private int size; SinglyLinkedList() { head = new SListNode(null, null); size = 0; } … } public SinglyLinkedList implements List { private SListNode head; private int size; SinglyLinkedList() { head = new SListNode(null, null); size = 0; } … } If in an empty list head is not null then the list uses sentinel nodes.

23 Sentinal Node Example public void addToFront(Object o) { head.setNext(new SListNode(o, head.getNext()); size++; } public void addToFront(Object o) { head.setNext(new SListNode(o, head.getNext()); size++; } public Object removeFirst() { if(isEmpty()) { throw new NoSuchElementException(); } SListNode node = head.getNext(); head.setNext(head.getNext().getNext()); size--; return node.getData(); } public Object removeFirst() { if(isEmpty()) { throw new NoSuchElementException(); } SListNode node = head.getNext(); head.setNext(head.getNext().getNext()); size--; return node.getData(); } public void addToFront(Object o) { head = new SListNode(o, head); size++; } public void addToFront(Object o) { head = new SListNode(o, head); size++; } public Object removeFirst() { if(isEmpty()) { throw new NoSuchElementException(); } SListNode node = head; head = head.getNext(); size--; return node.getData(); } public Object removeFirst() { if(isEmpty()) { throw new NoSuchElementException(); } SListNode node = head; head = head.getNext(); size--; return node.getData(); } Sentinel NodesNo Sentinel Nodes

24 Singly-Linked List Performance MethodRun-time performance void add(int index, Object element) O(n) boolean add(Object element) O(1) void clear() O(1) Object get(int index) O(n) int indexOf(Object element) O(n) Object remove(int index) O(n) Object set(int index, Object element) O(n)

25 List Implementation Doubly-Linked Implementation: Uses a recursively-defined list node structure to hold data elements Has dynamic capacity with little wasted memory Keep track of the head and tail nodes and can access all other nodes Natural operations are from the head and tail since they are fast Next Prev Head Node Data Next Prev Data Next Prev Data Tail Node

26 Doubly Linked List class DListNode { private DListNode previous, next; private Object data; DListNode(Object d) { data = d; next = null; previous = null; } DListNode(Object d, DListNode p, DListNode n) { data = d; previous = p; next = n; } // accessors and mutators } Each node is a link in a chain of nodes. Each node can see forward AND backward Each node contains a data element.

27 Doubly Linked List class DoublyLinkedList implements List{ private DListNode head, tail; private int size; DoublyLinkedList() { head = null; tail = null; size = 0; } public void addToFront(Object o) { … } public void addToTail(Object o) { … } public Object removeFirst() { … } public Object removeLast() { … } // other methods } The list keeps track of the first link (called the head ) from which all other links can be accessed. interface List{ public void addToFront(Object o); public void addToTail(Object o); public Object removeFirst(); public Object removeLast(); public Object first(); public Object last(); public int size(); public boolean isEmpty(); }

28 Add To Front Operation Next Prev Head Node Data Next Prev Data Next Prev Data Tail Node tail head size: 3 public void addToFront(Object o) { head = new DListNode(o, null, head); if(head.getNext() != null) { head.getNext().setPrevious(head); } if(tail == null) tail = head; size++; } public void addToFront(Object o) { head = new DListNode(o, null, head); if(head.getNext() != null) { head.getNext().setPrevious(head); } if(tail == null) tail = head; size++; } What needs to be done to insert an item at the head of this list?

29 Remove First Operation Next Prev Data Next Prev Data Next Prev Data tail head size: 3 public Object removeFirst() { if(isEmpty()) { throw new NoSuchElementException(); } Object result = head.getData(); head = head.getNext(); if(head != null) { head.setPrevious(null); } else { tail = null; } size--; return result; } public Object removeFirst() { if(isEmpty()) { throw new NoSuchElementException(); } Object result = head.getData(); head = head.getNext(); if(head != null) { head.setPrevious(null); } else { tail = null; } size--; return result; } What needs to be done to remove an item at the head of this list?

30 Front Operations Example public void addToFront(Object o) { head = new DListNode(o, null, head); if(head.getNext() != null) { head.getNext().setPrevious(head); } if(tail == null) tail = head; size++; } public void addToFront(Object o) { head = new DListNode(o, null, head); if(head.getNext() != null) { head.getNext().setPrevious(head); } if(tail == null) tail = head; size++; } public Object removeFirst() { if(isEmpty()) { throw new NoSuchElementException(); } Object result = head.getData(); head = head.getNext(); if(head != null) { head.setPrevious(null); } else { tail = null; } size--; return result; } public Object removeFirst() { if(isEmpty()) { throw new NoSuchElementException(); } Object result = head.getData(); head = head.getNext(); if(head != null) { head.setPrevious(null); } else { tail = null; } size--; return result; } List list = new DoublyLinkedList(); for(int i=0; i<3; i++) { list.addToFront(new Integer(i)); } while(!list.isEmpty()) { System.out.println(list.removeFirst()); } List list = new DoublyLinkedList(); for(int i=0; i<3; i++) { list.addToFront(new Integer(i)); } while(!list.isEmpty()) { System.out.println(list.removeFirst()); }

31 Add To Tail Operation public void addToTail(Object o) { tail = new DListNode(o, tail, null); if(tail.getPrevious() != null) { tail.getPrevious().setNext(tail); } if(head == null) head = tail; size++; } public void addToTail(Object o) { tail = new DListNode(o, tail, null); if(tail.getPrevious() != null) { tail.getPrevious().setNext(tail); } if(head == null) head = tail; size++; } public void addToFront(Object o) { head = new DListNode(o, null, head); if(head.getNext() != null) { head.getNext().setPrevious(head); } if(tail == null) tail = head; size++; } public void addToFront(Object o) { head = new DListNode(o, null, head); if(head.getNext() != null) { head.getNext().setPrevious(head); } if(tail == null) tail = head; size++; } Since it is a doubly-linked list – the list looks the same both forward and backward. The methods are symmetrical!

32 Remove From Tail Operation public Object removeFirst() { if(isEmpty()) { throw new NoSuchElementException(); } Object result = head.getData(); head = head.getNext(); if(head != null) { head.setPrevious(null); } else { tail = null; } size--; return result; } public Object removeFirst() { if(isEmpty()) { throw new NoSuchElementException(); } Object result = head.getData(); head = head.getNext(); if(head != null) { head.setPrevious(null); } else { tail = null; } size--; return result; } public Object removeLast() { if(isEmpty()) { throw new NoSuchElementException(); } Object result = tail.getData(); tail = tail.getPrevious(); if(tail != null) { tail.setNext(null); } else { head = null; } size--; return result; } public Object removeLast() { if(isEmpty()) { throw new NoSuchElementException(); } Object result = tail.getData(); tail = tail.getPrevious(); if(tail != null) { tail.setNext(null); } else { head = null; } size--; return result; } The remove methods are also highly symmetrical.

33 public Object removeLast() { if(isEmpty()) { throw new NoSuchElementException(); } Object result = tail.getData(); tail = tail.getPrevious(); if(tail != null) { tail.setNext(null); } else { head = null; } size--; return result; } public Object removeLast() { if(isEmpty()) { throw new NoSuchElementException(); } Object result = tail.getData(); tail = tail.getPrevious(); if(tail != null) { tail.setNext(null); } else { head = null; } size--; return result; } Tail Operations Example List list = new DoublyLinkedList(); for(int i=0; i<3; i++) { list.addToTail(new Integer(i)); } while(!list.isEmpty()) { System.out.println(list.removeLast()); } List list = new DoublyLinkedList(); for(int i=0; i<3; i++) { list.addToTail(new Integer(i)); } while(!list.isEmpty()) { System.out.println(list.removeLast()); } public void addToTail(Object o) { tail = new DListNode(o, tail, null); if(tail.getPrevious() != null) { tail.getPrevious().setNext(tail); } if(head == null) head = tail; size++; } public void addToTail(Object o) { tail = new DListNode(o, tail, null); if(tail.getPrevious() != null) { tail.getPrevious().setNext(tail); } if(head == null) head = tail; size++; }

34 Doubly-Linked List Performance MethodRun-time performance void add(int index, Object element) O(n) boolean add(Object element) O(1) void clear() O(1) Object get(int index) O(n) int indexOf(Object element) O(n) Object remove(int index) O(n) Object set(int index, Object element) O(n)

35 List Implementation Sentinel nodes: Implementation technique to simplify the code Can be used with either doubly or singly linked lists Head (and tail) nodes are dummy nodes that hold no data Head (and tail) nodes never change and are always present Next Prev Head Node Data Next Prev Data Next Prev Data Tail Node Sentinel nodes contain no data

36 A Simple Problem Problem: Given a List – write a method to print the contents of the list without modifying the list! interface List{ public void addToFront(Object o); public void addToTail(Object o); public Object removeFirst(); public Object removeLast(); public Object first(); public Object last(); public int size(); public boolean isEmpty(); } interface List{ public void addToFront(Object o); public void addToTail(Object o); public Object removeFirst(); public Object removeLast(); public Object first(); public Object last(); public int size(); public boolean isEmpty(); } public void printList(List list) { for(int i=0; i

37 Enumerations!!! A better solution is to use an Enumeration An interface in the java.util package Gives sequential read-only access to the contents of a linear collection Don t need to know anything about the collection implementation public void printList(List list) { Enumeration e = list.elements(); while(e.hasMoreElements()) { System.out.println(e.nextElement()); } public void printList(List list) { Enumeration e = list.elements(); while(e.hasMoreElements()) { System.out.println(e.nextElement()); } interface Enumeration { public boolean hasMoreElements(); public Object nextElement(); } interface Enumeration { public boolean hasMoreElements(); public Object nextElement(); }

38 Enumeration class SinglyLinkedList implements List { private SListNode head; private int size; // other methods here Enumeration elements() { … } class SinglyLinkedList implements List { private SListNode head; private int size; // other methods here Enumeration elements() { … } } class SinglyLinkedListEnumeration implements Enumeration { private SListNode current; SinglyLinkedListEnumeration(SListNode n) { current = n; } public boolean hasMoreElements() { return current != null; } public Object nextElement() { if(!hasMoreElements()) { throw new NoSuchElementException(); } Object result = current.getData(); current = current.getNext(); return result; } class SinglyLinkedListEnumeration implements Enumeration { private SListNode current; SinglyLinkedListEnumeration(SListNode n) { current = n; } public boolean hasMoreElements() { return current != null; } public Object nextElement() { if(!hasMoreElements()) { throw new NoSuchElementException(); } Object result = current.getData(); current = current.getNext(); return result; } }

39 Java LinkedList Class Hierarchy LinkedList AbstractSequentialList AbstractList AbstractCollection Object


Download ppt "Linked Lists Linear collections. List Abstract Data Type List interface built-in to the collections framework The built-in List interface is a dynamic."

Similar presentations


Ads by Google