In this algorithm we create different threads for each of the elements in the input array and then each thread sleeps for an amount of time which is proportional to the value of corresponding array element. Hence, the thread having the least amount of sleeping time wakes up first and the number gets printed and then the second least element and so on. The largest element wakes up after a long time and then the element gets printed at the last. Thus the output is a sorted one. All this multithreading process happens in background and at the core of the OS. We do not get to know anything about what’s happening in the background, hence this is a “mysterious” sorting algorithm.
Example :
Let’s assume (for convenience) we have a computer that’s so slow it takes 3 seconds to work through each element:
INPUT: 8 2 9
3s: sleep 8
6s: sleep 2
8s: "2" (2 wakes up so print it)
9s: sleep 9
11s: "8" (8 wakes up so print it)
18s: "9" (9 wakes up so print it)
OUTPUT: 2 8 9
Implementation
To implement sleep sort, we need multithreading functions, such as
_beginthread()
and
WaitForMultipleObjects()
. Hence we need to include
windows.h
to use these functions. This won’t compile on
Online IDE
. We must run it in your PC (Note this code is for WINDOWS and not for LINUX). To perform a sleep sort we need to create threads for each of the value in the input array. We do this using the function
_beginthread()
. In each of the threads we assign two instructions:
1) Sleep
: Sleep this thread till arr[i] milliseconds (where arr[i] is the array element which this thread is associated to). We do this using Sleep() function. The Sleep(n) function suspends the activity associated with this thread till ‘n’ milliseconds. Hence if we write Sleep(1000), then it means that the thread will sleep for 1 second (1000 milliseconds = 1 second)
2) Print :
When the thread ‘wakes’ up after the sleep then print the array element – arr[i] which this thread is associated to. After creating the threads, we process these threads. We do this using
WaitForMultipleObjects()
.
CPP
#include <stdio.h>
#include <windows.h>
#include <process.h>
void routine( void *a)
{
int n = *( int *) a;
Sleep(n);
printf ("%d ", n);
}
void sleepSort( int arr[], int n)
{
HANDLE threads[n];
for ( int i = 0; i < n; i++)
threads[i] = ( HANDLE )_beginthread(&routine, 0, &arr[i]);
WaitForMultipleObjects(n, threads, TRUE, INFINITE);
return ;
}
int main()
{
int arr[] = {34, 23, 122, 9};
int n = sizeof (arr) / sizeof (arr[0]);
sleepSort (arr, n);
return (0);
}
|
Java
import java.util.ArrayList;
class SleepSort {
public static void main(String[] args) {
ArrayList<Integer> arr = new ArrayList<>();
arr.add( 34 );
arr.add( 23 );
arr.add( 122 );
arr.add( 9 );
sleepSort(arr);
}
public static void sleepSort(ArrayList<Integer> arr) {
ArrayList<Thread> threads = new ArrayList<>();
for ( int num : arr) {
Thread thread = new Thread(() -> {
try {
Thread.sleep(num);
System.out.print(num + " " );
} catch (InterruptedException e) {
e.printStackTrace();
}
});
threads.add(thread);
thread.start();
}
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
|
Python3
import threading
import time
def routine(num):
time.sleep(num / 1000.0 )
print (num, end = " " )
def sleep_sort(arr):
threads = []
for num in arr:
thread = threading.Thread(target = routine, args = (num,))
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
if __name__ = = "__main__" :
arr = [ 34 , 23 , 122 , 9 ]
sleep_sort(arr)
|
C#
using System;
using System.Collections.Generic;
using System.Threading;
class Program
{
static void Routine( int num)
{
Thread.Sleep(num);
Console.Write(num + " " );
}
static void SleepSort(List< int > arr)
{
List<Thread> threads = new List<Thread>();
foreach ( int num in arr)
{
Thread thread = new Thread(() => Routine(num));
threads.Add(thread);
thread.Start();
}
foreach (Thread thread in threads)
{
thread.Join();
}
}
static void Main( string [] args)
{
List< int > arr = new List< int > { 34, 23, 122, 9 };
SleepSort(arr);
}
}
|
Limitations
1) This algorithm won’t work for negative numbers as a thread cannot sleep for a negative amount of time. 2) Since this algorithm depends on the input elements, so a huge number in the input array causes this algorithm to slow down drastically (as the thread associated with that number has to sleep for a long time). So even if the input array element contains only 2 elements, like- {1, 100000000}, then also we have to wait for a much longer duration to sort. 3) This algorithm doesn’t produce a correct sorted output every time. This generally happens when there is a very small number to the left of a very large number in the input array. For example – {34, 23, 1, 12253, 9}. The output after sleep sorting is {9, 1, 23, 34, 1223} A wrong output also occurs when the input array is reverse sorted initially, like- {10, 9, 8, 7, 6, 5}. The reason for such an unexpected output is because some time is taken between scanning through each element as well as some other OS operations (like inserting each threads in a priority queue for scheduling). We cannot simply ignore the time taken by all these things. We describe this using the below example-
Let's assume (for convenience) we have a computer that's
so slow it takes 3 seconds to work through each element:
INPUT: 10 9 8 7 6 5
3s: sleep 10
6s: sleep 9
9s: sleep 8
12s: sleep 7
13s: "10" (10 wakes up so print it)
15s: sleep 6
15s: "9" (9 wakes up so print it)
17s: "8" (8 wakes up so print it)
18s: sleep 5
19s: "7" (7 wakes up so print it)
21s: "6" (6 wakes up so print it)
23s: "5" (5 wakes up so print it)
OUTPUT: 10 9 8 7 6 5
The above output is just an example. Obviously, modern-day computers computer are not so slow (to take 3 seconds to scan through each element). In reality running sleep sort on a modern computer on the above array gives the output – {9, 5, 7, 10, 8, 6}
How to fix this ?
1) We can fix this by repeatedly sleep sorting on the new output until the output becomes sorted. Every time it will sort the elements more accurately. 2) The wrong output as discussed earlier happens due to the time taken by other OS works and scanning through each element. In our program we have used the function
Sleep(arr[i])
, which means that each thread associated with the array elements sleep for ‘arr[i]’ milliseconds. Since milliseconds is a very small quantity and other OS tasks can take more time than ‘arr[i]’ milliseconds which ultimately can cause an error in sleep sorting. Increasing the sleeping time by even 10 times can give a sorted output as the OS tasks will finish all its task in between this much sleep, hence not producing any errors. Had we used
Sleep(10*arr[i])
instead of just Sleep(arr[i]) then we will certainly get a more precise output than the latter one. For example the input array – {10, 9, 8, 7, 6, 5} will give the correct sorted output – {5, 6, 7, 8, 9, 10} if we use Sleep(10*arr[i]) instead of just Sleep(arr[i]) . However it is still possible that Sleep(10*arr[i]) will give wrong results for some test cases. To make it more precise increase the sleep time more , say something like – Sleep(20*arr[i]). Hence the bottom line is that more the sleep time, more accurate the results are. (Sounds interesting, eh?) . But again that would increase the runtime of this algorithm.
Exercise to the readers-
1) The above algorithm tries to sort it in ascending order. Can you sort an input array in descending order using sleep sort. Think upon it. 2) Is it a comparison based sorting algorithm ? How many comparisons this algorithm makes ? [ Answer : No, it makes zero comparisons ] 3) Can we do sleeping sort without using windows.h header and without using Sleep() function? [One idea can be to create a priority queue where the elements are arranged according to the time left before waking up and getting printed. The element at the front of the priority queue will be the first one to get waked up. However the implementation doesn’t looks easy. Think on it.]
Time Complexity
Although there are many conflicting opinions about the time complexity of sleep sort, but we can approximate the time complexity using the below reasoning- Since Sleep() function and creating multiple threads is done internally by the OS using a priority queue (used for scheduling purposes). Hence inserting all the array elements in the priority queue takes O(Nlog N) time. Also the output is obtained only when all the threads are processed, i.e- when all the elements ‘wakes’ up. Since it takes O(arr[i]) time to wake the ith array element’s thread. So it will take a maximum of O(max(input)) for the largest element of the array to wake up. Thus the overall time complexity can be assumed as O(NlogN + max(input)), where, N = number of elements in the input array, and input = input array elements
Auxiliary Space
All the things are done by the internal priority queue of the OS. Hence auxiliary space can be ignored.
Conclusion
Sleep Sort is related to Operating System more than any other sorting algorithm. This sorting algorithm is a perfect demonstration of multi-threading and scheduling done by OS. The phrase “Sorting while Sleeping” itself sounds very unique. Overall it is a fun, lazy, weird algorithm. But as rightly said by someone- “If it works then it is not lazy”.
This article is contributed by
Rachit Belwariar
. If you like GeeksforGeeks and would like to contribute, you can also write an article and mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks. Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above
Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!
Last Updated :
16 Nov, 2023
Like Article
Save Article