A doubly linked list (DLL) is a data structure comprising nodes with pointers to the next as well as the previous node. In this Answer, we learn how to reverse a DLL.
Note: For a quick primer on DLLs, we can click here.
We can reverse a DLL in a similar manner to reversing a regular linked list. For this, we need three temporary pointers or nodes, including a tail
pointer. Unlike a regular linked list, though, we need to swap around double the number of pointers.
Here are the steps we must follow in our function:
tail
right at the start.NULL
.head
of the linked list.A visual representation of the steps above is as follows:
The driver code for our C++ doubly linked list implementation is given below. We coded it using templates. We can use any data type with the implementation, as long as it's consistent, without changing the code itself.
We can see below that we have two linked lists. One of these contains only int
values, while the other contains only char
values.
Note: If we just want to see the function for a reversal, we can look at the highlighted lines (138–162) in the
linked_list.cpp
file.
#ifndef __LIST_CPP#define __LIST_CPP#include "linked_list.h"#include <cstdlib>#include <iostream>using namespace std;// Constructor: Set both head and tail to NULLtemplate <class T>linked_list<T>::linked_list() {head = NULL;tail = NULL;}// Destructor: Memory management (very important)template <class T>linked_list<T>::~linked_list() {for(int i = 0; i < length(); i++) {delete_head();}}// Insert elements to the head (left) of the listtemplate <class T>void linked_list<T>::insert_head(T item) {if(head == NULL) {head = new list_item<T>(item);tail = head;return;}list_item<T> *Node = new list_item<T>(item);head->prev = Node;Node->next = head;head = Node;}// Insert elements to the tail (right) of the listtemplate <class T>void linked_list<T>::insert_tail(T item) {if(tail == NULL) {tail = new list_item<T>(item);head = tail;return;}list_item<T> *Node = new list_item<T>(item);tail->next = Node;Node->prev = tail;tail = Node;}// For checking purposestemplate <class T>list_item<T>* linked_list<T>::get_head() {return head;}// For checking purposestemplate <class T>list_item<T>* linked_list<T>::get_tail() {return tail;}// For the destructortemplate <class T>void linked_list<T>::delete_head() {if(head == NULL) {return;}else if(head->next == NULL) {delete head;head = NULL;tail = NULL;}else {list_item<T> *current = head->next;delete head;head = current;head->prev = NULL;}}// Good to havetemplate <class T>void linked_list<T>::delete_tail() {if(head == NULL) {return;}else if(head->next == NULL) {delete head;head = NULL;tail = NULL;}else {list_item<T> *current = tail->prev;delete tail;tail = current;tail->next = NULL;}}// For demonstration purposestemplate <class T>int linked_list<T>::length() {int count = 0;if(head == NULL) {return count;}else {list_item<T> *current = head;while(current != NULL) {count++;current = current->next;}return count;}}// For demonstration purposestemplate <class T>void linked_list<T>::print() {if(head == NULL) {cout << "empty list";} else {list_item<T> *current = head;while(current != NULL) {if(current->next != NULL) {cout << current->value << " <=> ";} else {cout << current->value;}current = current->next;}}}// The function we want to learn abouttemplate <class T>void linked_list<T>::reverse() {if(head == NULL) {cout << "empty list";} else {list_item<T> *before = head;list_item<T> *current = head->next;list_item<T> *after = head->next->next;while(current != NULL) {if(before->prev == NULL) {before->prev = current;before->next = NULL;tail = before;}current->next = before;current->prev = after;before = current;current = after;if(after != NULL) {after = after->next;}}head = before;}}#endif
Here's how the highlighted function in the code above works:
if
branch checks whether the linked list has any values or not.list_item
), so we make them here. We use before
and after
for bookkeeping and tying up loose ends. The current
pointer is largely responsible for traversing the linked list, and flipping the next
and prev
pointers of the nodes.if
in the loop ensures that the head
of the linked list converts into the tail
.if
in the loop ensures that when after
is first assigned to NULL
in the second-last iteration, it does not traverse further. Without this handling, the function throws a segmentation fault error.head
.