QuickSort on Doubly Linked List
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<->5Input: 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++ 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 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 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 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# 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 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.