Doubly Linked List Recallthatthe deletion ofan elem entatthe tailisnoteasy because w e have to find the node before the tail(the lastnode)by link hopping. head next elem ent next next next elem ent elem ent elem ent Baltim ore Rom e Seattle Toronto tail roblem can be easily solved by using the double lin - Ed. 2 and 3.: Chapter 4 - Ed. 4: Chapter 3
47
Embed
Doubly Linked List This problem can be easily solved by using the double linked list. - Ed. 2 and 3.: Chapter 4 - Ed. 4: Chapter 3.
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Doubly Linked List
Recall that the deletion of an element at the tail is not easy because we have to find the node before the tail (the last node) by link hopping.
head
next
element
next nextnext
element element element
Baltimore Rome Seattle Toronto
tail
This problem can be easily solved by using the double linked list.
- Ed. 2 and 3.: Chapter 4- Ed. 4: Chapter 3
A node in a doubly linked list: A com pound object that stores a reference to an elem ent and tw o references, called next and prev , to the next and previous nodes, respectively.
Reference tonext node
Reference to anelem ent
next
E lem ent
N ode
Reference toprevious node
prev
F o r c o n v e n i e n c e , a d o u b l y l i n k e d l i s t h a s a h e a d e r n o d e a n d a t r a i l e r n o d e . T h e y a r e a l s o c a l l e d s e n t i n e l n o d e s , i n d i c a t i n g b o t h t h e e n d s o f a l i s t .
h e a d e r
B a l t i m o r e R o m e S e a t t l e
t r a i l e r
Difference from singly linked lists:- each node contains two links.- two extra nodes: header and trailer, which contain no
elements.
Example:
5050
5060
5080
5070
5090
50A0
50B0
50D0
50C0
50E0
50F0
5110
5100
50C0
5060 50E05080
50D0
50800 next
Rome
Baltimore
Seattle
Node
prev
050500
5050
50A0
5060
0
5070
Element
5050
5060
5080
5070
5090
50A0
50B0
50D0
50C0
50E0
50F0
5110
5100
50C0
5060 50E05080
50D0
50800
Rome
Baltimore
Seattle
050500
5050
50A0
5060
0
5070
header
next
Node
prev
Element
5050
5060
5080
5070
5090
50A0
50B0
50D0
50C0
50E0
50F0
5110
5100
50C0
5060 50E05080
50D0
50800
Rome
Baltimore
Seattle
050500
5050
50A0
5060
0
5070
header
next
Node
prev
Element
5050
5060
5080
5070
5090
50A0
50B0
50D0
50C0
50E0
50F0
5110
5100
50C0
5060 50E05080
50D0
50800
Rome
Baltimore
Seattle
050500
5050
50A0
5060
0
5070
header
next
Node
prev
Element
5050
5060
5080
5070
5090
50A0
50B0
50D0
50C0
50E0
50F0
5110
5100
50C0
5060 50E05080
50D0
50800
Rome
Baltimore
Seattle
050500
5050
50A0
5060
0
5070
header
next
Node
prev
Element
5050
5060
5080
5070
5090
50A0
50B0
50D0
50C0
50E0
50F0
5110
5100
50C0
5060 50E05080
50D0
50800
Rome
Baltimore
Seattle
050500
5050
50A0
5060
0
5070trailer
header
next
Node
prev
Element
Class DLNodeHere is an implementation of nodes for doubly linked lists in Java: public class DLNode { private Object element; private DLNode next, prev; public DLNode() { this( null, null, null ); } public DLNode( Object e, DLNode p, DLNode n ) { element = e; next = n; prev = p; }
Deleting an element at the head is similar to deleting an element at the tail. Inserting an element at the tail is similar to inserting an element at the head. No link hopping is needed in any of the operations.
However, for inserting a node into the middle of a double linkedlist or deleting a node in the middle, link hopping is always needed.
public class NodeList implements List {
protected int numElts; // Number of elements in the list protected DNode header, trailer; // Special sentinels /** Constructor that creates an empty list; O(1) time */ public NodeList() { numElts = 0; header = new DNode(null, null, null); // create header trailer = new DNode(header, null, null); // create trailer header.setNext(trailer); // make header and trailer point to each other } /** Checks if position is valid for this list and converts it to * DNode if it is valid; O(1) time */ public DNode checkPosition(Position p) throws InvalidPositionException { if (p == null) throw new InvalidPositionException
("Null position passed to NodeList");
if (p == header)throw new InvalidPositionException ("The header node is not a valid position");
if (p == trailer)throw new InvalidPositionException ("The trailer node is not a valid position");
throw new InvalidPositionException ("Position does not belong to a valid NodeList");
return temp; } catch (ClassCastException e) { throw new InvalidPositionException
("Position is of wrong type for this list"); } }
/** Returns the number of elements in the list; O(1) time */ public int size() { return numElts; } /** Returns whether the list is empty; O(1) time */ public boolean isEmpty() { return (numElts == 0); } /** Returns the first position in the list; O(1) time */ public Position first() throws EmptyListException { if (isEmpty()) throw new EmptyListException("List is empty"); return header.getNext(); }
public Position last() throws EmptyContainerException { if (isEmpty())
throw new EmptyContainerException("List is empty"); return trailer.getPrev(); }
/** Returns the position before the given one; O(1) time */ public Position prev(Position p) throws InvalidPositionException, BoundaryViolationException { DNode v = checkPosition(p); DNode prev = v.getPrev(); if (prev == header) throw new BoundaryViolationException
("Cannot advance past the beginning of the list"); return prev; } /** Insert the given element before the given position, returning * the new position; O(1) time */ public Position insertBefore(Position p, Object element) throws InvalidPositionException { // DNode v = checkPosition(p); numElts++; DNode newNode = new DNode(v.getPrev(), v, element); v.getPrev().setNext(newNode); v.setPrev(newNode); return newNode; }
public Position insertLast(Object element) {numElts++; DNode newNode = new DNode(trailer.getPrev(), trailer, element);// System.out.println(((ONode)newNode.element()).inorderNum()); trailer.getPrev().setNext(newNode); trailer.setPrev(newNode); //trailer.getPrev().setNext(newNode); return newNode; }
public Position insertAfter(Position p, Object element) { DNode v = checkPosition(p); numElts++; DNode newNode = new DNode(v, v.getNext(), element); v.getNext().setPrev(newNode); v.setNext(newNode); return newNode;}
/** Insert the given element at the beginning of the list, returning * the new position; O(1) time */ public Position insertFirst(Object element) { numElts++; DNode newNode = new DNode(header, header.getNext(), element); header.getNext().setPrev(newNode); header.setNext(newNode); return newNode; }
/**Remove the given position from the list; O(1) time */ public Object remove(Position p) throws InvalidPositionException { DNode v = checkPosition(p); numElts--; DNode vPrev = v.getPrev(); DNode vNext = v.getNext(); vPrev.setNext(vNext); vNext.setPrev(vPrev); Object vElem = v.element(); // unlink the position from the list and make it invalid v.setNext(null); v.setPrev(null); return vElem; }
/** Replace the element at the given position with the new element * and return the old element; O(1) time */ public Object replace(Position p, Object element) throws InvalidPositionException { DNode v = checkPosition(p); Object oldElt = v.element(); v.setElement(element); return oldElt; }
public void swapElements(Position a, Position b)throws InvalidPositionException {
//System.out.println("swapElement is executed!!!"); DNode pA = checkPosition(a); DNode pB = checkPosition(b); Object temp = pA.element(); pA.setElement(pB.element()); pB.setElement(temp); }
public Position next(Position p) throws InvalidPositionException, BoundaryViolationException { DNode v = checkPosition(p); DNode next = v.getNext(); if (next == trailer) throw new BoundaryViolationException
("Cannot advance past the beginning of the list"); return next; }
public Iterator positions() {return new PositionIterator(this);
} public Iterator elements(){return new PositionIterator(this);}
}
Data Structure Exercises 6.1
Double-Ended Queues
R e c a l l t h a t a q u e u e h a s a f r o n t a n d a r e a r . E l e m e n t s c a n b e a d d e d a t t h e r e a r a n d c a n b e r e m o v e d a t t h e f r o n t .
F r o n t R e a r
N o w w e a l s o w a n t t o a d d e l e m e n t s a t t h e f r o n t a n d r e m o v e t h e m a t t h e r e a r .
Definition: A double-ended queue is a queue that supports insertion and deletion at both the front and the rear of the queue. deque: pronounciated as “deck”
The Deque Abstract Data TypeA deque D is an abstract data type that supports the following four fundamental methods: insertFirst(e): Insert a new element e at the beginning of D.
Input: Object; Output: None. insertLast(e): Insert a new element e at the end of D.
Input: Object; Output: None. removeFirst(): Remove and return the first element of D; an
error occurs if D is empty. Input: None; Output: Object
removeLast(): Remove and return the last element of D; an error occurs if D is empty. Input: None; Output: Object
Other supporting methods:
first(): Return the first element of D; an error occurs if D is empty Input: None; Output: Object
last(): Return the last element of D; an error occurs if D is empty Input: None; Output: Object
size(): Return the number of elements of D. Input: None; Output: integer
isEmpty(): Determine if D is empty. Input: None; Output: Boolean
Recall that elements can be inserted and deleted easily at both the head and tail of a doubly linked list. Therefore, a deque can be implemented with a doubly linked list. Example:
header
Rome Seattle
trailer
BaltimoreToronto
Class MyDeque
public class MyDeque implements Deque { DLNode header, trailer; int size; public MyDeque() { header = new DLNode(); trailer = new DLNode(); header.setNext( trailer ); trailer.setPrev( header ); size = 0; }
header trailer
public Object first() throws DequeEmptyException { if( isEmpty() ) throw new DequeEmptyException( "Deque is empty." ); return header.getNext().getElement(); }
header
Baltimore
link hopping
public void insertFirst( Object o ) { DLNode second = header.getNext(); DLNode first = new DLNode( o, header, second ); second.setPrev( first ); header.setNext( first ); size++; }
headersecond
first
Object o
… …header
secondfirst
Object o
…
…
public Object removeLast() { if( isEmpty() ) throw new DequeEmptyException( "Deque is empty." ); DLNode last = trailer.getPrev(); Object o = last.getElement(); DLNode secondtolast = last.getPrev(); trailer.setPrev( secondtolast ); secondtolast.setNext( trailer ); size--; return o; }
trailersecondtolast last
Object o
…
trailersecondtolast
last
Object o
public Object last() throws DequeEmptyException {if( isEmpty() )throw new DequeEmptyException( "Deque is empty." );
return trailer.getPrev().getElement();}
public void insertLast( Object o ) {DLNode secondLast = trailer.getPrev();DLNode last = new DLNode( o, secondLast, trailer );secondLast.setNext( last );trailer.setPrev( last );size++;}
public int size( ) {return size;}
public boolean isEmpty( ) {return header.getNext() == trailer;}
…
trailersecondtolast
last
Object o
public Object removeFirst() {if( isEmpty() )
throw new DequeEmptyException( "Deque is empty." );DLNode first = header.getNext();Object o = first.getElement();DLNode second = first.getNext();header.setNext( second );second.setPrev( header );size--;return o;}
}public class GenerateDeque {
public static void main(String args[]) {MyDeque D = new MyDeque(); int i;for (i = 0; i < 10; i++) {
D.insertFirst(new Integer(i));}for (i = 0; i < 10; i++)
Stacks and queues can be easily implemented with a deque. All we need to do is to map the operations. Implementation of a stack with a deque: Stack Method Deque Implementation size() isEmpty() top() push(e) pop()
public class DequeStack implements Stack { private Deque D; public DequeStack() { D = new MyDeque(); } public int size() { return D.size(); } public boolean isEmpty() { return D.isEmpty(); } public void push( Object obj ) { D.insertLast( obj ); }