Quick Sort - Main Idea
- Select a node (Probably Head node) as Pivot Node
- Traverse through the remaining nodes to divide into two lists - one containing smaller or equal values and another containing larger values.
- Recursively apply the sort algorithm to two smaller lists. As a base case, the recursive method will return the input when the input list is of size 1 or 0.
- Merge First List, Pivot and Second List
Partition
Partition Method selects head node of given list as Pivot node. Based upon this pivot, the input list is divided into two smaller lists - First one with smaller or equal value and Second one with larger values.Return Type
This method will return an array of Three Nodes - First one is head of first list, Second is Pivot node and the Third is the head of the second list.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/**
* Partitions the given linked list. Takes O(n) time and O(1) space
*
* @param head head node of the linked list to be partitioned
* @return array of 3 elements, 1. head of first half 2. Pivot node and 3. head of second half
*/
public static ListNode[] partition(ListNode head) {
ListNode pivot = head;
ListNode node = head.next;
pivot.next = null;
ListNode firstHalfHead = null;
ListNode secondHalfHead = null;
while (node != null) {
ListNode curr = node;
node = node.next;
if (curr.val <= pivot.val) {
curr.next = firstHalfHead;
firstHalfHead = curr;
} else {
curr.next = secondHalfHead;
secondHalfHead = curr;
}
}
return new ListNode[]{firstHalfHead, pivot, secondHalfHead};
} // partition
Sort Helper
sortHelper() is the recursive method that recursively sorts the smaller lists to finally return the sorted list.Return Type
This method returns an array of two nodes - Head and Tail nodes of the Sorted List. They are required to ultimately merge the smaller lists and pivot.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/**
* Recursive helper method to sort the list. Recursively sorts the partitioned lists
* and finally return the merged list which is sorted.
* Average Case Time Complexity is O(nLogn) and Space Complexity is O(1)
* @param head
* @return
*/
public static ListNode[] sortHelper(ListNode head) {
if (head == null || head.next == null) return new ListNode[]{head, head};
ListNode[] partitions = partition(head);
ListNode[] firstHeadTail = sortHelper(partitions[0]);
ListNode[] secondHeadTail = sortHelper(partitions[2]);
return merge(firstHeadTail, partitions[1], secondHeadTail);
} // sortHelper
Merge
merge() method merges the two smaller sorted list and the pivot.Return Type
This method returns an array of two nodes - Head and Tail nodes of the Sorted List. They are required to ultimately merge the smaller lists and pivot.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/**
* Merges Two sorted lists and a pivot in between them. First list contains elements smaller than
* or equal to pivot and Seconds list contains elements greater than pivot
* Takes O(1) time and O(1) space
*
* @param firstHeadTail Array of Head and Tail Nodes of first sorted list
* @param pivot Pivot node
* @param secondHeadTail Array of Head and Tail Nodes of seconds sorted list
* @return
*/
public static ListNode[] merge(ListNode[] firstHeadTail, ListNode pivot, ListNode[] secondHeadTail) {
if (firstHeadTail[1] != null && secondHeadTail[1] != null) {
firstHeadTail[1].next = pivot;
pivot.next = secondHeadTail[0];
return new ListNode[]{firstHeadTail[0], secondHeadTail[1]};
} else if (firstHeadTail[1] != null) {
firstHeadTail[1].next = pivot;
return new ListNode[]{firstHeadTail[0], pivot};
} else {
pivot.next = secondHeadTail[0];
return new ListNode[]{pivot, secondHeadTail[1]};
}
} // merge
Complete Implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* File: SortLinkedList.java
* Created: 8/21/2018
* Author: Sabbir Manandhar
*
* Copyright (c) 2018 Hogwart Inc.
*/
//=======================================================================================
/**
* @author Sabbir Manandhar
* manandharsabbir@gmail.com
* @version 1.0
*/
public class QuickSortLinkedList {
/**
* main method
* @param args
*/
public static void main(String[] args) {
ListNode head = new ListNode(6);
ListNode newNode = new ListNode(7);
newNode.next = head;
head = newNode;
newNode = new ListNode(1);
newNode.next = head;
head = newNode;
newNode = new ListNode(3);
newNode.next = head;
head = newNode;
newNode = new ListNode(2);
newNode.next = head;
head = newNode;
newNode = new ListNode(9);
newNode.next = head;
head = newNode;
newNode = new ListNode(23);
newNode.next = head;
head = newNode;
newNode = new ListNode(5);
newNode.next = head;
head = newNode;
newNode = new ListNode(5);
newNode.next = head;
head = newNode;
newNode = new ListNode(15);
newNode.next = head;
head = newNode;
System.out.println(sort(head));
} // main
//-------------------------------------------------------------------------------------
/**
* Method to sort
* @param head head of the list to sort
* @return head of sorted list
*/
public static ListNode sort(ListNode head) {
return sortHelper(head)[0];
} // sort
//-------------------------------------------------------------------------------------
/**
* Recursive helper method to sort the list. Recursively sorts the partitioned lists
* and finally return the merged list which is sorted.
* Average Case Time Complexity is O(nLogn) and Space Complexity is O(1)
* @param head
* @return
*/
public static ListNode[] sortHelper(ListNode head) {
if (head == null || head.next == null) return new ListNode[]{head, head};
ListNode[] partitions = partition(head);
ListNode[] firstHeadTail = sortHelper(partitions[0]);
ListNode[] secondHeadTail = sortHelper(partitions[2]);
return merge(firstHeadTail, partitions[1], secondHeadTail);
} // sortHelper
//-------------------------------------------------------------------------------------
/**
* Merges Two sorted lists and a pivot in between them. First list contains elements smaller than
* or equal to pivot and Seconds list contains elements greater than pivot
* Takes O(1) time and O(1) space
*
* @param firstHeadTail Array of Head and Tail Nodes of first sorted list
* @param pivot Pivot node
* @param secondHeadTail Array of Head and Tail Nodes of seconds sorted list
* @return
*/
public static ListNode[] merge(ListNode[] firstHeadTail, ListNode pivot, ListNode[] secondHeadTail) {
if (firstHeadTail[1] != null && secondHeadTail[1] != null) {
firstHeadTail[1].next = pivot;
pivot.next = secondHeadTail[0];
return new ListNode[]{firstHeadTail[0], secondHeadTail[1]};
} else if (firstHeadTail[1] != null) {
firstHeadTail[1].next = pivot;
return new ListNode[]{firstHeadTail[0], pivot};
} else {
pivot.next = secondHeadTail[0];
return new ListNode[]{pivot, secondHeadTail[1]};
}
} // merge
//-------------------------------------------------------------------------------------
/**
* Partitions the given linked list. Takes O(n) time and O(1) space
*
* @param head head node of the linked list to be partitioned
* @return array of 3 elements, 1. head of first half 2. Pivot node and 3. head of second half
*/
public static ListNode[] partition(ListNode head) {
ListNode pivot = head;
ListNode node = head.next;
pivot.next = null;
ListNode firstHalfHead = null;
ListNode secondHalfHead = null;
while (node != null) {
ListNode curr = node;
node = node.next;
if (curr.val <= pivot.val) {
curr.next = firstHalfHead;
firstHalfHead = curr;
} else {
curr.next = secondHalfHead;
secondHalfHead = curr;
}
}
return new ListNode[]{firstHalfHead, pivot, secondHalfHead};
} // partition
} // QuickSortLinkedList
//=======================================================================================
class ListNode {
ListNode next;
int val;
//-------------------------------------------------------------------------------------
public ListNode(int data) {
this.val = data;
}
//-------------------------------------------------------------------------------------
public String toString() {
StringBuilder sb = new StringBuilder();
ListNode node = this;
while (node != null) {
sb.append(node.val + " ");
node = node.next;
}
return sb.toString();
} // toString
} // ListNode
No comments:
Post a Comment