180 likes | 193 Vues
Learn how to implement a LinkedList data structure in Java and C#, with examples and explanations of the different types of LinkedList implementations.
E N D
Linked Lists Revision Based on: http://www.academic.marist.edu/~jzbv/
Linked Lists • LinkedList is an important data structure in OO languages such as Java and C# • What you need to learn is how to write the implementation. • Our philosophical principle: in pursuit of absolute simplicity. • How: Divide, Conquer, and Glue
What to Do? • Interface IList is given • Two implementations are discussed: • Solution One: Doubly Linked List Class • Solution Two: Singly Linked List Class
Interface IList • Interface IList has the following methods: • boolean add( Object x) -- append to end of the list • boolean add(int i, Object x) – insert at position i • boolean remove(int i) – remove object at position i
Linked Lists A LinkedList implements the interface IList There are a number of ways in which a LinkedList can be implemented internally, but each implementation should provide the client (code that uses a LinkedList) with a single common set of operations that can be evoked by messages to the LinkedList object. Types of LinkedList implementations include: • Doubly linked list • Singly linked list We will examine how the main List operations are implemented in each of these alternatives
Linked Lists Doubly-linked List A LinkedList is a connected sequence of Nodes. It is composed of two classes of objects: LinkedLists and Nodes. class Node { //Node methods go here //attributes private Node pred, succ; private Object data; } class LinkedList implements IList { //class Node (see left) is declared here //implementation of List methods goes here //attributes private Node head, tail; privateint size; } Node is an internal class visible only to LinkedList objects. The private attributes: pred and succ, have class scope and are thus indirectly accessible via the setter/getter methods in class LinkedList. BUT for the illustration purpose, we treat them as protect, which you can set and get a value for them.
p pred pred data data succ succ Linked Lists Useful terminology for referring to Nodes in a LinkedList Nodes are not named objects, but are referred to by a “pointer” Node p = new Node(theObject); p.succ = new Node(nextObject); This is the the Node that p points to This Node is the successor of the Node that p points to
aList head size tail p p 24 21 Linked Lists LinkedList aList = new LinkedList( ); Integer temp = new Integer(21); Node p = new Node(temp); Integer temp = new Integer(24); Node p = new Node (temp); aList.add( new Integer(24) ); aList.add( new Integer(21) ); //head != 0 tail.succ = p; if (head == 0) head = p; tail = p; size++; p.pred = tail; tail = p; size++; 1 0 2
Linked Lists Putting it together publicboolean add (Object theObj) { Node p = new Node(theObj); if (head == 0) head = p; else { tail.succ = p; p.pred = tail; } tail = p; size++; return true; }
aList head size tail 10 21 24 p 3 Linked Lists Inserting an object at position i Integertemp = new Integer (3); Node p = new Node(temp); p.pred = 0; p.succ = head; if (head != 0) head.pred = p; 3 4 head = p; size++; Insert at front of the list (i == 0) The successor of Node referenced by p is Node referenced by head else (head ==0) -- inserting into an empty list -- set tail = p
aList head size tail 10 21 24 p 41 Linked Lists Inserting an object at position i Integertemp = new Integer (3); Node p = new Node(temp); if (i == size) { //insert at end p.pred = tail; p.succ = 0; tail.succ = p; 3 4 tail = p; size++; Inserting at end of non-empty list (i==size) p’ s predecessor is the Node tail points to Make Node p points to the successor of Node tail points to The Node p points to is now at the end of the list
aList head size tail q q q 10 21 24 p 23 Linked Lists Integertemp = new Integer (23); Node p = new Node(temp); Inserting an object at position i int count = 0; Node q = head; while (count < i) { count++; q = q.getNext( ); } 3 4 p.pred = q.getPrev( )); Inserting at general position – (0 <= i < size) count = 0 count = 1 p.succ = q; count = 2 q.getPrev( ).succ = p; //3 The order of these statements is important – statement 3 MUST precede statement 4. Move a handle to the Node at position i – Let i = 2 in this example Insert new Node before the Node that q points to. q.pred = p; //4 size++;
else { //insert at general position int count = 0; Node q = head; while (count < i) { count++; q = q.getNext( ); } p.pred = q.getPrev( ); p.succ = q; q.getPrev( ).succ = p; q.pred = p; } size++; return true; q.getPrev( ) returns a reference to the previous Node – Make the successor of that Node = p. } Linked Lists Putting it all together publicboolean add(int i, Object x) { if (i < 0 || i > size) { //range error System.err.println (“error – index out of range”); System.exit(1); //better – throw Exception } Node p = new Node(x); if (i ==0) { //insert at front p.pred = 0; //superfluous p.succ = head; if (head !=0) head.pred = p; else tail = p; head = p; } elseif (i == size) { //insert at end p.succ = 0; p.pred = tail; tail.succ = p; tail = p; }
aList head size tail p 41 21 24 Linked Lists Removing objects from a List Node p = head; if (i ==0) { //remove first Node head = p.getNext( ); if (head != 0) head.pred = 0; else //removing last node tail = 0; size--; } 3 2 Remove first Node – (i == 0) Automatic garbage collection reclaims the unreferenced Node when p goes out of scope.
aList head size tail p 41 21 24 Linked Lists if (i ==size-1) { //remove last Node p = tail; //Node * p; set previously if (head != tail) { tail.getPrev().succ = 0; tail = tail.getPrev( ); } else {//removing last node tail = 0; head = 0; } size--; } Removing objects from a List 3 2 Remove the last node – (i == size – 1) tail.getPrev( ) Automatic garbage collection reclaims memory when p goes out of scope
aList head size tail p p 41 21 24 Linked Lists Removing objects from a List Node p = head; int pos = 0; while (pos < i) { //find node to cut p = p.getNext( ); //move handle pos++; } p.getPrev( ).succ = p.succ; p.getNext( ).pred = p.pred; size--; } 3 2 p.getPrev( ) p.getNext( ) The Node referenced by p is deleted when p goes out of scope pos = 0 pos = 1 Remove Node in general position – ( i ==1)
Linked Lists Bringing it all back home elseif (i == size-1) { //remove last node p = tail; if (head != tail) { tail.getPrev.succ = 0; tail = tail.getPrev( ); } else { head = 0; tail = 0; } } //end else if else { //remove Node in general position p = head; int pos = 0; while (pos < i ) { //move handle p = p.getNext( ); pos++ } p.getPrev.succ = p.succ; p.getNext.pred = p.pred; } //end else p.setPrev(0); p.setNext(0); //for safety size--; return true; publicboolean remove(int i) { if (i < 0 || i >= size) { //range error System.err.println (“error – index out of range”); System.exit(1); } Node p; if (i == 0 ) // remove first node p = head; head = p.succ; if (head != 0) head.pred = 0; else tail = 0; } //end if } //end remove
aList size head tail p q p q p Linked Lists publicclass Node { public Node(Object x) {…} publicvoid setNext( ) {…} public Node getNext( ) {…} public Object getData( ) {…} private Node succ; private Object data; } Singly-linked Lists 3 data succ 21 24 47 pos = 0 pos =2 pos = 1 Implementing methods add( ) and remove( ) will be left as an exercise. To remove the Node at index pos, remove the Node that p references. Use the Node that q references to reattach the links. Move two handles in sequence until p reaches position i – (let i = 2) for(int pos = 0; pos < i; pos++) { q = p; p = p.getNext( ); } To perform an insert at pos, insert the new Node after the Node that q references and before the Node that p references Node p = head, q = head;