Doubly Linked List
There is a type of linked list that allows us to go in both directions—forward and reverse—in a linked list. It is the doubly linked list. In addition to its element member, a node in a doubly linked list stores two pointers, a next
link and a prev
link, which point to the next node in the list and the previous node in the list, respectively.
Such lists allow for a great variety of quick update operations, including efficient insertion and removal at any given position.
Header and Trailer Sentinels
To simplify programming, it is convenient to add special nodes at both ends of a doubly linked list: a header
node just before the head of the list, and a trailer
node just after the tail of the list. These “dummy” or sentinel nodes do not store any elements. They provide quick access to the first and last nodes of the list. In particular, the header’s next pointer points to the first node of the list, and the prev pointer of the trailer node points to the last node of the list.
Insertion in a Doubly Linked List
- Given node v, z, and w.
- Node v is the header node or any other node except for the tail node.
- Node z is the node to be inserted inbetween.
- Node w is the node that comes after node z.
v-next = w
w->prev = v
How to insert z between v and w
1 | z->prev = v; //1)Make z’s prev link point to v |
3.3.2 Removal from a Doubly Linked List
Given node v, z, and w. - Node v is the header node or any other node except for the tail node. - Node z is the node to be removed inbetween. - Node w is the node that comes after node z.
1 | w->prev = z->prev; //w->prev now points to v |
3.3.3 A C++ Implementation: doubly linked list
- a typedef statement that defines the element type, called Elem. We define it to be a string, but any other type could be used instead. Each node stores an element.
- pointers to both the
previous
andnext
nodes of the list. - We declare DLinkedList to be a friend, so it can access the node’s private members
- To keep the code simple, we have chosen not to derive a templated class as we did in Section 3.2.1 for singly linked lists.
1 | typedef string Elem; |
DLinkedList.cpp
1 | class DLinkedList { |
Chain Assignment: v->prev->next = v->prev = u;
Operator priority. the ->
are all realized before the assignment operator.
3.4 Circularly linked list
It is similar to a single link list - Has the same kind of node
The list is circular i.e., the last node points back at the first node - If the list has only one node, that node will point to itself.
There is no beginning or end, but nevertheless, a beginning spot is marked called the cursor
. - The first element referenced by the cursor is actually called the back, and the element immediately following is called the front.
- cursor is inserted before the head because it is the back of the queue
front(): Return the element referenced by the cursor; an error results if the list is empty.
back(): Return the element immediately after the cursor; an error results if the list is empty.
advance(): Advance the cursor to the next node in the list.
add(e): Insert a new node with element e immediately after the cursor; if the list is empty, then this node becomes the cursor and its next pointer points to itself.
NOTE: The DLinked List add function adds the node BEFORE the pointer. Here, in circular linked list, the node is added AFTER the pointer/cursor.
remove(): Remove the node immediately after the cursor (not the cursor itself, unless it is the only node); if the list becomes empty, the cursor is set to null.
Note: In The DLinked List, the remove function removes the Node itself that is passed. In circular, the node is removed immediately after the cursor.
(What if we did use a templated class? How would that look?))))To keep the code simple, we have not implemented a templated class. Instead, we provide a typedef statement that defines the element type Elem to be the base type of the list, which in this case is a string.
To keep the code simple, we have omitted error checking. In front, back, and advance, we should first test whether the list is empty, since otherwise the cursor pointer will be NULL. In the first two cases, we should throw some sort of exception. In the case of advance, if the list is empty, we can simply return
1 | typedef string Elem; //element type |
1 | playList.add("20"); |
Maintaining a Playlist for a Digital Audio Player
3.4.2 Reversing a Linked List
As another example of the manipulation of linked lists, we present a simple function
for reversing the elements of a doubly linked list. Given a list L, our approach
involves first copying the contents of L in reverse order into a temporary list T, and
then copying the contents of T back into L (but without reversing).
To achieve the initial reversed copy, we repeatedly extract the first element of
L and copy it to the front of T. (To see why this works, observe that the later an
element appears in L, the earlier it will appear in T.) To copy the contents of T
back to L, we repeatedly extract elements from the front of T, but this time we
copy each one to the back of list L. Our C++ implementation is presented in Code
Fragment 3.35.
1 | void listReverse(DLinkedList& L) { // reverse a list |