XOR Linked List – A Memory Efficient Doubly Linked List | Set 1

24 Jun, 2022
An ordinary Doubly Linked List requires space for two address fields to store the addresses of previous and next nodes. It is represented as follows in the image below. From the below image, it can be depicted out that the address of the previous node is retained and carried over for computation by the previous pointer while that of the next node is after pointers similarly. 
 Now there is a memory-efficient version of Doubly Linked List that can be created using only one space for the address field with every node. This memory efficient Doubly Linked List is called XOR Linked List or Memory Efficient as the list uses bitwise XOR operation to save space for one address. In the XOR linked list, instead of storing actual memory addresses, every node stores the XOR of addresses of previous and next nodes. 
Consider the above Doubly Linked List. Following are the Ordinary and XOR (or Memory Efficient) representations of the Doubly Linked List.  
Now here we will be discussing out both the ways in order to perch out how XOR representation behaves differently from ordinary representation.
Ordinary RepresentationXOR List Representation
Ordinary Representation
XOR List Representation
Way 1: Ordinary Representation
Node A: 
prev = NULL, next = add(B) // previous is NULL and next is address of B 
Node B: 
prev = add(A), next = add(C) // previous is address of A and next is address of C 
Node C: 
prev = add(B), next = add(D) // previous is address of B and next is address of D 
Node D: 
prev = add(C), next = NULL // previous is address of C and next is NULL 
Way 2: XOR List Representation
Let us call the address variable in XOR representation npx (XOR of next and previous) 
While traversing XOR Linked List we can traverse the XOR list in both forward and reverse directions. While traversing the list we need to remember the address of the previously accessed node in order to calculate the next node’s address. 
For example: When we are at node C, we must have the address of B. XOR of add(B) and npx of C gives us the add(D).
Illustration:
Node A: 
npx = 0 XOR add(B) // bitwise XOR of zero and address of B 
Node B: 
npx = add(A) XOR add(C) // bitwise XOR of address of A and address of C 
Node C: 
npx = add(B) XOR add(D) // bitwise XOR of address of B and address of D 
Node D: 
npx = add(C) XOR 0 // bitwise XOR of address of C and 0 
npx(C) XOR add(B) 
=> (add(B) XOR add(D)) XOR add(B) // npx(C) = add(B) XOR add(D)
=> add(B) XOR add(D) XOR add(B) // a^b = b^a and (a^b)^c = a^(b^c)
=> add(D) XOR 0  // a^a = 0
=> add(D)     // a^0 = a
Similarly, we can traverse the list in the backward direction. Now straightaway coming down to the implementation part in order to figure out better.
Implementation:
C++
// C++ Implementation of Memory// efficient Doubly Linked List  // Importing libraries#include <bits/stdc++.h>#include <cinttypes>  using namespace std;  // Class 1// Helper class(Node structure)class Node {    public : int data;    // Xor of next node and previous node    Node* xnode;};  // Method 1// It returns Xored value of the node addressesNode* Xor(Node* x, Node* y){    return reinterpret_cast<Node*>(        reinterpret_cast<uintptr_t>(x)        ^ reinterpret_cast<uintptr_t>(y));}  // Method 2// Insert a node at the start of the Xored LinkedList and// mark the newly inserted node as headvoid insert(Node** head_ref, int data){    // Allocate memory for new node    Node* new_node = new Node();    new_node -> data = data;      // Since new node is inserted at the    // start , xnode of new node will always be    // Xor of current head and NULL    new_node -> xnode = *head_ref;      // If linkedlist is not empty, then xnode of    // present head node will be Xor of new node    // and node next to current head */    if (*head_ref != NULL) {        // *(head_ref)->xnode is Xor of (NULL and next).        // If we Xor Null with next we get next        (*head_ref)            -> xnode = Xor(new_node, (*head_ref) -> xnode);    }      // Change head    *head_ref = new_node;}  // Method 3// It simply prints contents of doubly linked// list in forward directionvoid printList(Node* head){    Node* curr = head;    Node* prev = NULL;    Node* next;      cout << "The nodes of Linked List are: \n";      // Till condition holds true    while (curr != NULL) {        // print current node        cout << curr -> data << " ";          // get address of next node: curr->xnode is        // next^prev, so curr->xnode^prev will be        // next^prev^prev which is next        next = Xor(prev, curr -> xnode);          // update prev and curr for next iteration        prev = curr;        curr = next;    }}  // Method 4// main driver methodint main(){    Node* head = NULL;    insert(&head, 10);    insert(&head, 100);    insert(&head, 1000);    insert(&head, 10000);      // Printing the created list    printList(head);      return (0);}
The nodes of Linked List are: 
10000 1000 100 10 
mr0kaushik
sumitgumber28
hardikkoriintern
Bitwise-XOR
doubly linked list
Advanced Data Structure
Linked List
Linked List
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
AVL Tree | Set 1 (Insertion)
Trie | (Insert and Search)
LRU Cache Implementation
Agents in Artificial Intelligence
Introduction of B-Tree
Linked List | Set 1 (Introduction)
Linked List | Set 2 (Inserting a node)
Reverse a linked list
Stack Data Structure (Introduction and Program)
LinkedList in Java