44
Chapter 22 Implementing lists: linked implementations

Chapter 22 Implementing lists: linked implementations

Embed Size (px)

Citation preview

Page 1: Chapter 22 Implementing lists: linked implementations

Chapter 22Implementing lists: linked implementations

Page 2: Chapter 22 Implementing lists: linked implementations

This chapter discusses

Linked lists lists built through object

references. dynamic lists. linked implementations of

structures more complex than a simple sequence.

Page 3: Chapter 22 Implementing lists: linked implementations

A linked list implementation If the list is not empty

there is a first element there is a last element every element (except the last)

has a successor every element (except the first)

has a predecessor

Page 4: Chapter 22 Implementing lists: linked implementations

A linked list implementation (cont.) An array structure is built by creating a

reference to the collection of list elements which are stored sequentially in memory.

A linked list is built by creating a reference to a node of the list that, in turn contains a reference to another node of the list, etc.

Page 5: Chapter 22 Implementing lists: linked implementations

LinkedList class

public abstract class LinkedList implements Cloneable {

private class Node { /**

* Create a Node containing specified element.

* /

public Node (Object element) {

this.element = element;

this.next = null;

}

Object element;

Node next;

}

}

Page 6: Chapter 22 Implementing lists: linked implementations

LinkedList class (cont.)

public abstract class LinkedList implements Cloneable {/**

* Create a Node containing specified element.

* /

protected LinkedList () {

size = 0;

first = null;

}…

private int size;

private Node first;

}

}

Page 7: Chapter 22 Implementing lists: linked implementations

LinkedList class (cont.)

Page 8: Chapter 22 Implementing lists: linked implementations

LinkedList class (cont.)

The component next of the last Node always has a value of null.

For the empty list, the LinkedList component first is null.

Page 9: Chapter 22 Implementing lists: linked implementations

LinkedList methods:getpublic Object get (int i) {

Node p = first;

int pos = 0;

while (pos < i) {

p = p.next;

pos = pos + 1;

}

return p.element;

}

Page 10: Chapter 22 Implementing lists: linked implementations

LinkedList methods:get (cont.) The variable p is initialized with a

reference to the 0-th Node of the list.

Page 11: Chapter 22 Implementing lists: linked implementations

LinkedList methods:get (cont.) Each iteration of the loop assigns p

a reference to the next element of the list and increments pos.

Page 12: Chapter 22 Implementing lists: linked implementations

LinkedList methods:get (Cont). Loop invariant: p references the

Node containing the element with index pos.

At loop termination pos == i p references the Node we are

looking for.

Page 13: Chapter 22 Implementing lists: linked implementations

LinkedList methods:append First, find the last element of list

Page 14: Chapter 22 Implementing lists: linked implementations

LinkedList methods:append (cont.) Create a new Node containing the element to

be appended Set the old last Node’s next component to

reference the new Node.

public void append (Object obj) {if (this.isEmpty()) first = new Node(obj);else { Node p = first; while (p.next != null);

p = p.next; p.next = new Node(obj);}size = size + 1;

}

Page 15: Chapter 22 Implementing lists: linked implementations

LinkedList methods: remove First, find the Node in front of the

one we want to delete.

Page 16: Chapter 22 Implementing lists: linked implementations

LinkedList methods: remove (cont.) Take next of the Node before the one to

be deleted and reference it the same as the next field of the Node to be deleted.

Page 17: Chapter 22 Implementing lists: linked implementations

LinkedList methods: remove (cont.) Since p.next is the Node to be

deleted, p.next cannot be null. Removing the first element of the

list is a special case.

Page 18: Chapter 22 Implementing lists: linked implementations

LinkedList methods: remove (cont.)

public void remove (int i) {if (i == 0) { first = first.next;else { Node p = first; int pos = 0; while (pos < i-1) {

p = p.next;pos = pos + 1;

} p.next = p.next.next;}size = size - 1;

}

Page 19: Chapter 22 Implementing lists: linked implementations

LinkedList methods: add

Page 20: Chapter 22 Implementing lists: linked implementations

LinkedList methods: add (cont.)public add (int i, Object obj) {

Node newElement = new Node(obj);if (i == 0) { newElement.next = first; first = newElement;} else { Node p = first; int pos = 0; while (pos < i-1) {

p = p.next;pos = pos + 1;

} newElement.next = p.next; p.next = newElement;}size = size + 1;

}

Page 21: Chapter 22 Implementing lists: linked implementations

LinkedList methods:

get, append, remove, and add all require linear time on average.

Deleting the first element and inserting a new first element, are constant time operations.

We must be particularly careful of “boundary” cases: cases involving the empty list a list with one element the first or last element of a list

These may well require explicit handling.

Page 22: Chapter 22 Implementing lists: linked implementations

LinkedList variations A simple change will make append a constant time operation.

We keep a reference to both the first and last elements in the list.

Page 23: Chapter 22 Implementing lists: linked implementations

LinkedList variations (cont.)public append (Object obj) {

Node newElement = new Node(obj);

if (this.isEmpty())

first = newElement;

else

last.next = newElement;

last = newElement;

size = size + 1;

}

Page 24: Chapter 22 Implementing lists: linked implementations

LinkedList variations (cont.) remove must now check explicitly

for the case in which the last element is deleted.

public void remove (int i) {if (size == 1) { // remove the only element first = null; last = null;} else if (i == 0) { // remove the first element first = first.next;}

Page 25: Chapter 22 Implementing lists: linked implementations

LinkedList variations (cont.)

else { Node p = first; int pos = 0; while (pos < i-1) {

p = p.nextpos = pos + 1;

} p.next = p.next.next; if (i == size-1) //last element removed

last = p;}size = size - 1;

}

Page 26: Chapter 22 Implementing lists: linked implementations

Header nodes

One way to eliminate special cases is to employ a header node.

It contains no element, but is always present at the front of the list. i.e. it is referenced by first.

Page 27: Chapter 22 Implementing lists: linked implementations

Header nodes (cont.)

private class Header extends Node {

public Header () {

this.element = null;

this.next = null;

}

}

The LinkedList constructor creates the header.

protected LinkedList () {

size = 0;

first = new Header();

last = first;

}

Page 28: Chapter 22 Implementing lists: linked implementations

Header nodes (cont.)

The method append, need not check explicitly for the empty list.

public append (Object obj) {

Node newElement = new Node(obj);

last.next = newElement;

last = newElement;

size = size + 1;

}

Page 29: Chapter 22 Implementing lists: linked implementations

Circular lists In a circular list, the last node references

the first. A circular list may or may not have a

header. We can traverse the entire list starting

from any node. Care must be taken to avoid infinite

iterations or recursions.

Page 30: Chapter 22 Implementing lists: linked implementations

Doubly-linked lists

Each node contains references to the preceding as well as to the following node.

Page 31: Chapter 22 Implementing lists: linked implementations

Doubly-linked lists (cont.) Three components:

the list elements references to its two neighboring nodes.

public abstract class DoublyLinkedList implements Cloneable {…private int size;private Node header;private class Node { public Node (Object element) {

this.element = element;this.next = null;this.previous = null;

} Object element; Node next; Node previous;}

}

Page 32: Chapter 22 Implementing lists: linked implementations

Doubly-linked lists (cont.)protected DoublyLinkedList () {

size = 0;

header = new Header();

header.next = header;

header.previous = header;

}

Page 33: Chapter 22 Implementing lists: linked implementations

Doubly-linked lists (cont.) Operations are a bit more complicated

since we have two references in each node, but the combination of a circular structure and a header eliminates the need for handling most boundary cases explicitly.

Page 34: Chapter 22 Implementing lists: linked implementations

DoublyLinkedList: append Set previous of the new node to

reference the old last node. Set next of the new node to reference

the header. Set previous of the header to reference

the new node. Set next component of the old last node

to reference the new node.

Page 35: Chapter 22 Implementing lists: linked implementations

DoublyLinkedList: append (cont.)public void append (Object obj) {

Node newElement = new Node(obj);

Node last = header.previous;

newElement.next = header;

newElement.previous = last;

last.next = newElement;

header.previous = newElement;

size = size + 1;

}

Page 36: Chapter 22 Implementing lists: linked implementations

Linked list limitations

Accessing elements by index is a linear time operation.

The get operation is linear. Therefore, any operation using the get method will be slower than in an array-based implementation.

public boolean contains (List list, Object obj) {int n = list.size();int i = 0;while (i < n && !obj.equals(list.get(i)) i = i + 1;}return i < n;

}

Page 37: Chapter 22 Implementing lists: linked implementations

Linked list limitations (cont.) This method can be implemented

without get.

public boolean contains (LinkedList list, Object obj) {Node p = list.first;while (p != null && !obj.equals(p.element)) p = p.next;}return p != null;

}

Page 38: Chapter 22 Implementing lists: linked implementations

Dynamic storage allocation automatic allocation: memory space for

automatic variables is allocated when the method is invoked, and reclaimed (“deallocated”) when the method completes.

Memory space for array elements is allocated when the array is created.

For a linked implementation, space required for a node is allocated when the node is created.

Page 39: Chapter 22 Implementing lists: linked implementations

Garbage collection

Dynamically allocated space that can no longer be accessed is termed garbage.

If we create an object and then loose all references to the object, the memory space occupied by the object becomes garbage.

Page 40: Chapter 22 Implementing lists: linked implementations

Garbage collection (cont.) The Java run-time system or interpreter

continuously looks for garbage and reclaims the space (garbage collection).

Many programming languages do not include garbage collection as part of their run-time systems.

They require programs to deallocate explicitly dynamically allocated space.

In an object-oriented environment, it is often difficult to know when an object no longer is accessible.

Page 41: Chapter 22 Implementing lists: linked implementations

Garbage collection (cont.) Dangling references are references to

space that has been reclaimed mistakenly.

Such references result in errors that often are extremely difficult to track down.

Page 42: Chapter 22 Implementing lists: linked implementations

We’ve covered

Linked structures nodes headers

Doubly-linked lists Circular lists Time complexities Dynamic storage allocation

garbage collection

Page 43: Chapter 22 Implementing lists: linked implementations

Glossary

Page 44: Chapter 22 Implementing lists: linked implementations

Glossary (cont.)