Вы находитесь на странице: 1из 20

A Doubly Linked List

There’s the need to access a list in reverse order

prev data next

dnode

header
Doubly Linked List Implementation
template <typename T>
class dnode
{
public:
// the members of a dnode object are used for operations within a
// doubly linked list; access is simplified by making them public

T nodeValue; // data value of the node


dnode<T> *prev; // previous node in the list
dnode<T> *next; // next node in the list

// default constructor. creates object with value T(), the default value
// of type T. set the node pointers to point at the node itself
dnode();

// constructor with an argument to initialize nodeValue.


// set the node pointers to point at the node itself
dnode(const T& value): nodeValue(value);
};
Default and Copy Constructors
Constructor creates an empty list by assigning this to both left and
right.

template <typename T>


dnode<T>::dnode()
{
next = this; // the next node is the current node
prev = this; // the previous node is the current node
}

template <typename T>


dnode<T>::dnode(const T& value): nodeValue(value)
{
next = this; // the next node is the current node
prev = this; // the previous node is the current node

}
Node Insertion
prevNode current node

prev next prev

prev next

newNode
dnode<T> *newNode, *prevNode;
// allocate a new node and assign prevNode to reference the predecessor of curr
newNode = new dnode<T>(item);
prevNode = curr->prev;

// update pointer fields in newNode


newNode->prev = prevNode;
newNode->next = curr;

// update curr and its predecessor to point to newNode


prevNode->next = newNode;
curr->prev = newNode;
The insert() Function
template <typename T>
dnode<T> *insert(dnode<T> *curr, const T& item)
{
// declare pointer variables for the new node and the previous node
dnode<T> *newNode, *prevNode;

// allocate new dnode with item as initial value


newNode = new dnode<T>(item);

// assign prevNode the pointer value of node before p


prevNode = curr->prev;

// update pointer fields in newNode


newNode->prev = prevNode;
newNode->next = curr;

// update curr and prevNode to point at newNode


prevNode->next = newNode;
curr->prev = newNode;

return newNode;
}
Node Deletion – Self Removal
curr
prevNode succNode

prev next prev next prev next

dnode<T> *prevNode = curr->prev, *succNode = curr->next;

prevNode -> next = succNode;


succNode -> prev = prevNode;

delete curr;
The erase() Function
template <typename T>
void erase(dnode<T> *curr)
{
// return if the list is empty
if (curr->next == curr)
return;

// declare pointers for the predecessor and successor nodes


dnode<T> *prevNode = curr->prev, *succNode = curr->next;

// update pointer fields for predecessor and successor


prevNode->next = succNode;
succNode->prev = prevNode;

// deallocate the memory used by the node


delete curr;
}
Circular Doubly Linked Lists
header

Simplify coding.
Avoid tests to determine if the list is empty.
Remove the additional code for updating the head pointer.

prev next
header An empty circular
linked list

header -> next == header


header-> prev == header
Scanning a Doubly Linked List
template <typename T>
void writeDlinkedList(dnode<T>* header, const string& separator = “ “)
{
// header points at first dnode. p moves through the list
dnode<T> *p = header->next;

while (p != header)
{
cout << p->nodeValue << separator;
p = p->next;
}
}
Application: The Josephus Problem
n customers to compete in a contest for a free world cruise.

The customers are placed in a circle by a travel agent.

The agent draws a number m (m  n) from a hat.

He rotates clockwise about the circle and stop at every mth


contestant.

This person is then removed from the game.

The game continues with every mth person eliminated until


only one remains.

The survivor is the winner!


A Game Example
n = 10
m=5
1
2
10

3
9
The winner!

8 4

5
7
6
Solution to the Josephus Problem
void josephus(int n, int m)
{
// declare the circular doubly linked list dList and scan pointer
dnode<int> *dList = new dnode<int>, *curr;
int i, j;

// initialize the list of contestants 1 2 3 ... n


for (i = 1; i <= n; i++)
insert(dList, i);

// curr moves around the list, starting at person 1


curr = dList->next;

// delete all but one person from the list


for (i=1; i < n; i++)
{
// counting current person at curr, visit m persons.
// we must advance m-1 times.
for (j=1; j <= m-1; j++)
{
// advance the pointer
curr = curr->next;
Solution (cont’d)
// if curr at the header, move again
if (curr == dList)
curr = curr->next;
}

cout << "Delete contestant " << curr->nodeValue << endl;

// advance curr and erase the node we just left


curr = curr->next;
erase(curr->prev);

// might have deleted the rear of the list, so


// curr is now at the header. move again
if (curr == dList)
curr = curr->next;
}

cout << endl << "Contestant " << curr->nodeValue


<< " wins the cruise" << endl;

// delete the one remaining node and the list header


delete curr;
delete dList;
}
The Main Program
void main() Enter the number of contestants? 10
{ Generated the random number 5
// numContestants is number of contestants Delete person 5
// removeM is the rotation selector Delete person 10
randomNumber rnd; Delete person 6
int n, m; Delete person 2
Delete person 9
cout << "Enter the number of contestants: "; Delete person 8
cin >> n; Delete person 1
Delete person 4
// generate a random number between 1 Delete person 7
// and numContestants
m = 1 + rnd.random(n); Contestant 3 wins the cruise.
cout << "Generated the random number "
<< m << endl;

// solve the Josephus problem and output the cruise winner


josephus(n, m);
}
The miniList Class
A variation of the STL list class.

A doubly linked list as the underlying structure.

Implementation of an iterator.

Private members:

dnode<T> *header;

int listSize;

dnode<T> *getDNode(const T& item); // allocate a dnode

dnode<T> *dinsert(dnode<T> *curr, const T& item); // insert before node curr and
// return address of the new node

void derase(dnode<T> *curr); // erase node curr from the linked list
A Constructor

template <typename T>


miniList<T>::miniList(int n, const T& value): listSize(n)
{
int i;

// create an empty list


header = new dnode<T>;
if (header == NULL)
throw memoryAllocationError
(“miniList(): memory allocation failure”);
// insert n copies of value at the front of the list
for (i = 0; i < n; i++)
dinsert(header->next, value);
}
Copy Constructor
template <typename T>
miniList<T>::miniList(const miniList<T>& obj): listSize(obj.listSize)
{
// curr moves through the nodes in obj, and end marks the finish
// of a traversal through obj
dnode<T> *curr = obj.header->next, *end = obj.header;

// create an empty list


header = new dnode<T>;
if (header == NULL)
throw memoryAllocationError
(“miniList(): memory allocation failure”);

// insert the values in the linked list obj.header at the back of the current list
while (curr != end)
{
dinsert(header, curr->nodeValue); // before the header, i.e., back of the list
curr = curr -> next;
}
}
Iterator Nested Class
class iterator
template <typename T> {
class miniList public:
{ friend class miniList<T>;
public:
// include the iterator // needed by the const_iterator constructor
// that converts a const iterator to a const_iterator
// nested classes friend class const_iterator;
#include “d_liter.h”
… // constructor
iterator() {}
private:
dnode<T> *header; bool operator==(const iterator& rhs) const;
int listSize; bool operator!= (const iterator& rhs) const;
T& operator* (); // pointer dereference operator
iterator& operator++ ();
dnode<T> *getDNode(
iterator operator++ (int) ; // postfix increment. move forward one no
const T& item); iterator& operator-- ();
dnode<T> *dinsert( iterator operator-- (int);
dnode<T> *curr, const T& item);
void derase(dnode<T> *curr); private:
}; dnode<T> *nodePtr; // pointer to the current list node

// private constructor. converts p to an iterator


// by assigning p to nodePtr
iterator(dnode<T> *p): nodePtr(p) {}
Implementing Iterator Operations
T& operator* ()
{
// if the node's successor is itself, the list is empty
if (nodePtr->next == nodePtr)
throw referenceError("miniList iterator: reference error");
return nodePtr->nodeValue;
}

iterator& operator++ ()
{
nodePtr = nodePtr->next; // move to the successor of nodePtr
return *this; // return new iterator value
}

iterator operator++ (int)


{
// save the current value of the iterator
iterator tmp = *this;

// move to the successor of nodePtr


nodePtr = nodePtr->next;
return tmp; // return original iterator value
}
begin() and insert()
Both are member functions of class miniList.

template <typename T>


miniList<T>::iterator miniList<T>::begin()
{
return iterator(header->next);
}

template <typename T>


miniList<T>::iterator miniList<T>::insert(iterator pos, const T& item)
{
dnode<T> *curr = pos.nodePtr, *newNode;
// insert item before curr and capture the new node’s address
newNode = dinsert(curr, item);

// increment the list size


listSize++;

// constructor converts newNode to an iterator


return iterator(newNode);
}

Вам также может понравиться