Open In App

QuickSort on Doubly Linked List

Last Updated : 17 Sep, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

Given a doubly linked list, the task is to sort the doubly linked list in non-decreasing order using the quicksort.

Examples:

Input: head: 5<->3<->4<->1<->2
Output: 1<->2<->3<->4<->5
Explanation: Doubly Linked List after sorting using quicksort technique is 1<->2<->3<->4<->5

Input: head: 1<->5<->2<->3
Output: 1<->2<->3<->5
Explanation: Doubly Linked List after sorting using quicksort technique is 1<->2<->3<->5

Approach:

The quicksort algorithm for a doubly linked list sorts the list by selecting a pivot node and partitioning the list into two segments, nodes less than the pivot and nodes greater than or equal to the pivot. The pivot is placed in its correct position, and then the algorithm recursively sorts the segments on either side of the pivot. This partitioning and recursive sorting continue until the entire list is sorted. The process efficiently handles the doubly linked list by adjusting pointers to maintain the list structure throughout the sorting operation.

Below is the implementation of the above approach:

C++
// C++ program to sort a doubly linked list 
// using quicksort
#include <iostream>
using namespace std;

class Node {
public:
    int data;
    Node* next;
    Node* prev;

    Node(int x) {
        data = x;
        next = nullptr;
        prev = nullptr;
    }
};

// Function to swap the data of two nodes
void swap(Node* a, Node* b) {
  
    // Swap the data in the nodes
    int temp = a->data;
    a->data = b->data;
    b->data = temp;
}

// Function to partition the list and find pivot
Node* partition(Node* low, Node* high) {
  
    // Set pivot to the high node
    int pivot = high->data;

    // Pointer to place smaller elements
    Node* i = low->prev;

    // Traverse the list to rearrange nodes
    for (Node* j = low; j != high; j = j->next) {
        
        // If current node's data is less than or 
        // equal to the pivot
        if (j->data <= pivot) {
            
            // Move i forward and swap with j
            i = (i == nullptr) ? low : i->next;
            swap(i, j);
        }
    }

    // Move i to the correct pivot position
    i = (i == nullptr) ? low : i->next;
  
    // Swap pivot with i's data
    swap(i, high);

    return i;
}

// Recursive function to apply quicksort
void quickSort(Node* low, Node* high) {
  
    // Base case: if the list has one element or 
    // invalid range
    if (low != nullptr && high != nullptr 
        && low != high && low != high->next) {
      
        // Find the partition node (pivot)
        Node* pivot = partition(low, high);

        // Recursively sort the left half
        quickSort(low, pivot->prev);

        // Recursively sort the right half
        quickSort(pivot->next, high);
    }
}

// Function to get the last node of the list
Node* getLastNode(Node* head) {
  
    // Traverse to the end of the list
    while (head != nullptr && head->next != nullptr) {
        head = head->next;
    }
  
    return head;
}

void printList(Node* node) {
    Node* curr = node;
    while (curr != nullptr) {
        cout << " " << curr->data;
        curr = curr->next;
    }
}

int main() {
  
    // Create a hard-coded doubly linked list:
    // 5 <-> 3 <-> 4 <-> 1 <-> 2
    Node* head = new Node(5);
    head->next = new Node(3);
    head->next->prev = head;
    head->next->next = new Node(4);
    head->next->next->prev = head->next;
    head->next->next->next = new Node(1);
    head->next->next->next->prev = 
                     head->next->next;
    head->next->next->next->next = new Node(2);
    head->next->next->next->next->prev = 
                     head->next->next->next;

    Node* last = getLastNode(head);
    quickSort(head, last);
    printList(head);

    return 0;
}
C
// C program to sort a doubly linked list
// using quicksort
#include <stdio.h>
#include <stdlib.h>

struct Node {
    int data;
    struct Node* next;
    struct Node* prev;
};

// Function to swap the data of two nodes
void swap(struct Node* a, struct Node* b) {
  
    // Swap the data in the nodes
    int temp = a->data;
    a->data = b->data;
    b->data = temp;
}

// Function to partition the list and find pivot
struct Node* partition(struct Node* low,
                       struct Node* high) {

    // Set pivot to the high node
    int pivot = high->data;

    // Pointer to place smaller elements
    struct Node* i = low->prev;

    // Traverse the list to rearrange nodes
    for (struct Node* j = low; j != high;
         j = j->next) {
      
        // If current node's data is less than 
        // or equal to the pivot
        if (j->data <= pivot) {
            
            // Move `i` forward and swap with `j`
            i = (i == NULL) ? low : i->next;
            swap(i, j);
        }
    }

    // Move `i` to the correct pivot position
    i = (i == NULL) ? low : i->next;
    
    // Swap pivot with `i`'s data
    swap(i, high);

    return i;
}

// Recursive function to apply quicksort
void quickSort(struct Node* low, struct Node* high) {
  
    // Base case: if the list has one element or 
    // invalid range
    if (low != NULL && high != NULL 
        && low != high && low != high->next) {
      
        // Find the partition node (pivot)
        struct Node* pivot = partition(low, high);

        // Recursively sort the left half
        quickSort(low, pivot->prev);

        // Recursively sort the right half
        quickSort(pivot->next, high);
    }
}

// Function to get the last node of the list
struct Node* getLastNode(struct Node* head) {
  
    // Traverse to the end of the list
    while (head != NULL && head->next != NULL) {
        head = head->next;
    }
    return head;
}

void printList(struct Node* node) {
    struct Node* curr = node;
    while (curr != NULL) {
        printf("%d ", curr->data);
        curr = curr->next;
    }
}

struct Node* createNode(int new_data) {
    struct Node* new_node =
      (struct Node*)malloc(sizeof(struct Node));
    new_node->data = new_data;
    new_node->next = NULL;
    new_node->prev = NULL;
    return new_node;
}

int main() {

    // Create a hard-coded doubly linked list:
    // 5 <-> 3 <-> 4 <-> 1 <-> 2
    struct Node* head = createNode(5);
    head->next = createNode(3);
    head->next->prev = head;
    head->next->next = createNode(4);
    head->next->next->prev = head->next;
    head->next->next->next = createNode(1);
    head->next->next->next->prev = 
                     head->next->next;
    head->next->next->next->next = createNode(2);
    head->next->next->next->next->prev = 
                     head->next->next->next;

    struct Node* last = getLastNode(head);

    quickSort(head, last);
  
    printList(head);

    return 0;
}
Java
// Java program to sort a doubly linked list
// using quicksort
class Node {
    int data;
    Node next, prev;
  
    Node(int x) {
        data = x;
        next = null;
        prev = null;
    }
}

public class GfG {

    // Function to swap data of two nodes
    static void swap(Node a, Node b) {

        // Swap data between `a` and `b`
        int temp = a.data;
        a.data = b.data;
        b.data = temp;
    }

    // Function to partition the list around pivot
    static Node partition(Node low, Node high) {

        // Set pivot to the data of `high` node
        int pivot = high.data;

        // Pointer to place smaller elements
        Node i = low.prev;

        // Traverse list from `low` to `high`
        for (Node j = low; j != high; j = j.next) {

            // If current data is <= pivot
            if (j.data <= pivot) {
                
                // Move `i` forward and swap with `j`
                i = (i == null) ? low : i.next;
                swap(i, j);
            }
        }

        // Move `i` to correct pivot position
        i = (i == null) ? low : i.next;

        // Swap pivot data with `i`'s data
        swap(i, high);

        return i;
    }

    // Recursive quicksort function
    static void quickSort(Node low, Node high) {

        // Base case: stop recursion when invalid range
        if (low != null && high != null &&
            low != high && low != high.next) {

            // Partition the list and get the pivot node
            Node pivot = partition(low, high);

            // Recursively sort the left half
            quickSort(low, pivot.prev);

            // Recursively sort the right half
            quickSort(pivot.next, high);
        }
    }

    // Function to get the last node of the list
    static Node getLastNode(Node head) {

        // Traverse to the end of the list
        while (head != null && head.next != null) {
            head = head.next;
        }
        return head;
    }

    static void printList(Node node) {
        
        Node curr = node;
        while (curr != null) {
            System.out.print(" " + curr.data);
            curr = curr.next;
        }
    }

    public static void main(String[] args) {

        // Create a hard-coded doubly linked list:
        // 5 <-> 3 <-> 4 <-> 1 <-> 2
        Node head = new Node(5);
        head.next = new Node(3);
        head.next.prev = head;
        head.next.next = new Node(4);
        head.next.next.prev = head.next;
        head.next.next.next = new Node(1);
        head.next.next.next.prev = head.next.next;
        head.next.next.next.next = new Node(2);
        head.next.next.next.next.prev = 
                                head.next.next.next;


        Node last = getLastNode(head);

        quickSort(head, last);

        printList(head);
    }
}
Python
# Python program to sort a doubly linked list
# using quicksort
class Node:
    
    def __init__(self, data):
        self.data = data
        self.next = None
        self.prev = None

# Function to swap data between two nodes
def swap(a, b):
    
    # Swap the data between node `a` and node `b`
    a.data, b.data = b.data, a.data

# Partition function for quicksort
def partition(low, high):
    
    # Set pivot as the data of `high` node
    pivot = high.data

    # Pointer to place smaller elements
    i = low.prev

    # Traverse from `low` to `high`
    curr = low
    while curr != high:
        
        # If current node's data is <= pivot
        if curr.data <= pivot:
            
            # Move `i` forward and swap with `curr`
            i = low if i is None else i.next
            swap(i, curr)
        
        curr = curr.next

    # Move `i` to the correct pivot position
    i = low if i is None else i.next

    # Swap pivot data with `i`'s data
    swap(i, high)
    
    return i

# Recursive quicksort function
def quick_sort(low, high):
    
    # Base case: stop when invalid range
    if low and high and low != high and low != high.next:
        
        # Partition the list and get the pivot node
        pivot = partition(low, high)

        # Recursively sort the left half
        quick_sort(low, pivot.prev)

        # Recursively sort the right half
        quick_sort(pivot.next, high)

# Function to get the last node of the list
def get_last_node(head):
    
    # Traverse to the last node
    while head and head.next:
        head = head.next
    return head

def print_list(node):
    curr = node
    while curr:
        print(curr.data, end=" ")
        curr = curr.next

if __name__ == '__main__':
    
    # Create a hard-coded doubly linked list:
    # 5 <-> 3 <-> 4 <-> 1 <-> 2
    head = Node(5)
    head.next = Node(3)
    head.next.prev = head
    head.next.next = Node(4)
    head.next.next.prev = head.next
    head.next.next.next = Node(1)
    head.next.next.next.prev = head.next.next
    head.next.next.next.next = Node(2)
    head.next.next.next.next.prev = head.next.next.next

    last_node = get_last_node(head)

    quick_sort(head, last_node)

    print_list(head)
C#
// C# program to sort a singly linked list 
// using quicksort 
using System;

public class Node {
  
    public int data;
    public Node next;
  
    public Node(int new_data) {
        data = new_data;
        next = null;
    }
}

class GfG {
  
    // Function to swap data between two nodes
    static void Swap(Node a, Node b) {
        
        // Swap data between node `a` and node `b`
        int temp = a.data;
        a.data = b.data;
        b.data = temp;
    }

    // Partition function for quicksort
    static Node Partition(Node low, Node high) {
        
        // Set pivot as the data of `high` node
        int pivot = high.data;

        // Pointer to place smaller elements
        Node i = low;

        // Traverse from `low` to `high`
        Node curr = low;
        while (curr != high) {
            
            // If current node's data is <= pivot
            if (curr.data <= pivot) {
                
                // Swap data between `i` and `curr`
                Swap(i, curr);
                
                // Move `i` forward
                i = i.next;
            }
            curr = curr.next;
        }

        // Swap pivot data with `i`'s data
        Swap(i, high);
        return i;
    }

    // Recursive quicksort function
    static void QuickSort(Node low, Node high) {
        
        // Base case: stop when invalid range
        if (low != high && low != null && high != null) {
            
            // Partition the list and get the pivot node
            Node pivot = Partition(low, high);

            // Recursively sort the left half
            Node beforePivot = low;
            while (beforePivot != null
                    && beforePivot.next != pivot) {
                beforePivot = beforePivot.next;
            }

            // Sort left of pivot only if exists
            if (beforePivot != null && beforePivot != pivot)
                QuickSort(low, beforePivot);

            // Recursively sort the right half
            if (pivot != null && pivot.next != high)
                QuickSort(pivot.next, high);
        }
    }

    // Function to get the last node of the list
    static Node GetLastNode(Node head) {
        
        // Traverse the list to find the last node
        while (head != null && head.next != null) {
            head = head.next;
        }
        return head;
    }

    static void PrintList(Node node) {
        Node curr = node;
        while (curr != null) {
            Console.Write(" " + curr.data);
            curr = curr.next;
        }
    }

    static void Main(string[] args) {
        
        // Create a hard-coded linked list:
        // 5 -> 3 -> 4 -> 1 -> 2
        Node head = new Node(5);
        head.next = new Node(3);
        head.next.next = new Node(4);
        head.next.next.next = new Node(1);
        head.next.next.next.next = new Node(2);

        Node lastNode = GetLastNode(head);

        QuickSort(head, lastNode);

        PrintList(head);
    }
}
JavaScript
// JavaScript program to sort a doubly linked list
// using quicksort
class Node {
    constructor(data) {
        this.data = data;
        this.next = null;
        this.prev = null;
    }
}

// Function to swap the data between two nodes
function swap(a, b) {
    let temp = a.data;
    a.data = b.data;
    b.data = temp;
}

// Partition function for quicksort
function partition(low, high) {

    // Set pivot as the data of `high` node
    let pivot = high.data;

    // Pointer to place smaller elements
    let i = low.prev;

    // Traverse from `low` to `high`
    for (let j = low; j !== high; j = j.next) {
        if (j.data <= pivot) {
            i = (i === null) ? low : i.next;
            swap(i, j);
        }
    }

    // Swap pivot data with `i.next`'s data
    i = (i === null) ? low : i.next;
    swap(i, high);
    return i;
}

// Recursive quicksort function
function quickSort(low, high) {
    if (low !== null && high !== null && low !== high 
                                  && low !== high.next) {
        let pivot = partition(low, high);

        // Sort left side of the pivot
        quickSort(low, pivot.prev);

        // Sort right side of the pivot
        quickSort(pivot.next, high);
    }
}

// Function to get the last node of the list
function getLastNode(head) {
    while (head !== null && head.next !== null) {
        head = head.next;
    }
    return head;
}

function printList(node) {
    let curr = node;
    while (curr !== null) {
        console.log(" " + curr.data);
        curr = curr.next;
    }
}

// Create a hard-coded doubly linked list:
// 5 <-> 3 <-> 4 <-> 1 <-> 2
let head = new Node(5);
head.next = new Node(3);
head.next.prev = head;
head.next.next = new Node(4);
head.next.next.prev = head.next;
head.next.next.next = new Node(1);
head.next.next.next.prev = head.next.next;
head.next.next.next.next = new Node(2);
head.next.next.next.next.prev = head.next.next.next;

let lastNode = getLastNode(head);

quickSort(head, lastNode);

printList(head);

Output
 1 2 3 4 5

Time Complexity: On average, quicksort has a time complexity of O(nlogn), where n is the number of nodes. In the worst case (e.g., already sorted list), it becomes O(n²).
Auxiliary Space: O(logn) due to the recursion stack in average cases, and O(n) in the worst case.


Next Article

Similar Reads