Revolutionary sort algorithm

I can take credit for the code, but not the algorithm. Someones of yous can probably improve this:

int input[] = {47, 58, 19, 63, 37, 81, 22, 93, 12, 70, 54, 33, 29, };
const byte nItems = sizeof input / sizeof *input;

int output[nItems];

unsigned long dwell[nItems];
bool sorted[nItems];
unsigned long now;

void setup() {
  Serial.begin(115200);
  Serial.println("\nSort!\n");

  for (byte ii = 0; ii < nItems; ii++) {
    dwell[ii] = input[ii];
  }

  byte nDone = 0;
  while (nDone < nItems) {
    now = millis();    
    for (byte ii = 0; ii < nItems; ii++) {
      if (sorted[ii]) continue;   
      if (now >= dwell[ii]) {
        output[nDone] = input[ii];
        sorted[ii] = true;
        nDone++;
      }
    }
  }

  for (byte ii = 0; ii < nItems; ii++) {
    Serial.print(output[ii]);
    Serial.print(" ");
  }

  Serial.println("");
}

void loop() {
}

Oh, chatGPT wrote me the list of random numbers for input.

a7

Who gets credit for the algorithm?

BTW, notice the effect of an insignificant variation in the input data on overall sort timing:

int input[] = {30000, 58, 19, 63, 37, 81, 22, 93, 12, 70, 54, 33, 29, };
const byte nItems = sizeof input / sizeof *input;

int output[nItems];

unsigned long dwell[nItems];
bool sorted[nItems];
unsigned long now;

void setup() {
  Serial.begin(115200);
  Serial.println("\nSort!\n");

  for (byte ii = 0; ii < nItems; ii++) {
    dwell[ii] = input[ii];
  }

  byte nDone = 0;
  while (nDone < nItems) {
    now = millis();    
    for (byte ii = 0; ii < nItems; ii++) {
      if (sorted[ii]) continue;   
      if (now >= dwell[ii]) {
        output[nDone] = input[ii];
        sorted[ii] = true;
        nDone++;
      }
    }
  }

  for (byte ii = 0; ii < nItems; ii++) {
    Serial.print(output[ii]);
    Serial.print(" ");
  }

  Serial.println("");
}

void loop() {
}

I would not exactly call it revolutionary, and as @jremington pointed out, it will get very lengthy if you decide to sort large number (say up into the millions).

How do you handle the case where millis() increments by two (this does happen)? That would potentially sort a larger number located near the start of the array before a number that is 1 less, but located farther into the array.

It would be safer, and faster, to use an incrementing counter instead of millis(), but still not a great way to sort anything besides small numbers.

This implements the "incrementing counter" idea suggested by @david_2018, and works as expected for the data array examples already presented.

I also changed how the length of the data array was determined.

int input[] = {47, 58, 19, 63, 37, 81, 22, 93, 12, 70, 54, 33, 29};
const byte nItems = sizeof input / sizeof (input[0]);

int output[nItems];

unsigned long dwell[nItems];
bool sorted[nItems];
unsigned long now;

void setup() {
  Serial.begin(115200);
  Serial.println("\nSort!\n");

  for (byte ii = 0; ii < nItems; ii++) {
    dwell[ii] = input[ii];
  }
  long loopcount=0;  //incrementing counter
  byte nDone = 0;
  while (nDone < nItems) {
    now = loopcount++;    
    for (byte ii = 0; ii < nItems; ii++) {
      if (sorted[ii]) continue;   
      if (now >= dwell[ii]) {
        output[nDone] = input[ii];
        sorted[ii] = true;
        nDone++;
      }
    }
  }

  for (byte ii = 0; ii < nItems; ii++) {
    Serial.print(output[ii]);
    Serial.print(" ");
  }

  Serial.println("");
}

Why is it revolutionary?
What makes it different from thousands of already developped sorting algorithms?
What are the special features?
How does it scale?

It's fun, has been around for some time.

The concept of time-based sorting, where elements are "sorted" based on physical or temporal properties, dates back to early mechanical and physical implementations of sorting systems. Such methods predate digital computing and include techniques like sorting by gravity or using fluid flow in sorting processes. In the early 20th century, grain or sand was sometimes sorted using mechanisms that relied on timing and physical properties, such as density or size, to separate.

Time-based sorting has not made it to a standard algorithm in computer science though as it is highly inefficient.

1 Like

why not just increment now each iteration?

it would be safer and faster than millis() indeed

also if N-1 elements have been sorted, then you don't need to wait for the last one, you know it's the last in the array.

wouldn't compare to an N log(N) sort. would depend on the largest value (e.g. 1000000).

don't see any benefit to this approach. bubble sort was my first programming exercise

1 Like

As I mentioned in my previous comment, you need to be particularly careful with millis(), because on some Arduino's the millis() function will occasionally increment by 2 instead of 1. This is the result of using an 8-bit counter that cannot exactly divide the clock into 1mS intervals.

yes, that's why I said safer. Your point was correct.

I fault myself for taking my eye so off the ball (misspent years!) I had not seen the Sleep Sort until a friend (?) showed me this. I don't recognize the language but can see how it works:

  const arr = [120, 5, 100,1, 90, 200, 40, 29];
  for (let item of arr){
    setTimeout ( () =>
    console. log (item), item)
  }

which while not presented in the context of a full compiles we can play with it ourselves example is nevertheless a remarkably compact implementation of the algorithm.

All good questions one might ask of any "new" sorting idea. Can there be new ideas? I certainly hope so, but around sorting I would expect it all to have been pretty much sorted.

Revolutionary: click bait, sry.

Different: it uses a method I had not seen and can only imagine the kind of brain that dreamt it up. I dunno who claims it; I found more than one person who at least implied they created it.

Special features: Use, or more accurately abuse of system timing or task schedulers or whatever.

Scaling: It doesn't do negative numbers, unless as someone clever observed "Negative numbers will simply cause the print to be executed in the past. This would still result in the same order." And of course if you numbers are 20000 and 30000 and like that, it can take some large amount of real time.

Read and see implementations in a variety of languages:

The Sleep Sort is also not stable.

The incrementing counter fixes the millis() problem, but moves the algorithm away from its charter - use of time.

Another sort of sort that turns up when searching for fun and meaning I present here. I'll drop a clue for y'all by naming it the Fisher-Yates sort:

int input[] = {4, 1, 5, 9, 2, 6,};   // 5, 3, };   // 8 takes long enough, haven't tried 9
int n = sizeof input / sizeof *input;

void setup() {
  Serial.begin(9600);

  Serial.print("Initial array: ");
  printArray(input, n);

  sort(input, n);

  Serial.print("Sorted array: ");
  printArray(input, n);
}

void loop() {
}

void sort(int *arr, int n) {
  while (!test(arr, n))
    shuffle(arr, n);
}

bool test(int *arr, int n) {
  for (int ii = 0; ii < n - 1; ii++) {
    if (arr[ii] > arr[ii + 1]) {
      return false;
    }
  }
  return true;
}

void shuffle(int *arr, int n) {
  for (int ii = n - 1; ii > 0; ii--) {
    int jj = random(ii + 1);
    int temp = arr[ii];
    arr[ii] = arr[jj];
    arr[jj] = temp;
  }
}

void printArray(int *arr, int n) {
  for (int ii = 0; ii < n; ii++) {
    Serial.print(arr[ii]);
    Serial.print(" ");
  }
  Serial.println();
}

This is a horrible algorithm but it does work, eventually. Or does it? I wonder if the PRNG might get into some rhythm with the process and cause it to enter into an infinite loop.

I put this in General as in the past stuff that does not have questions about programming and/or is presented for amusement purposes or to stimulate conversation has been summarily moved out of Programming. To General.

a7

1 Like

feels like JavaScript

save this as a .htm file

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sleep Sort</title>
</head>
<body>
    <h1>Sleep Sort</h1>
    <p>Array: [120, 5, 100, 1, 90, 200, 40, 29]</p>
    <button id="runButton">Run Loop</button>
    <p>Output:</p>
    <pre id="output"></pre>
    <script>
        const arr = [120, 5, 100, 1, 90, 200, 40, 29];

        document.getElementById('runButton').addEventListener('click', () => {
            const outputDiv = document.getElementById('output');
            outputDiv.textContent = ''; // Clear previous output
            for (let item of arr) {
                setTimeout(() => {
                    outputDiv.textContent += `${item}\n`;
                }, item);
            }
        });
    </script>
</body>
</html>

and then you can see it in action (the array is hardwired)

1 Like

Depending on the N (and the PRNG), there could be orders that would not be generated in the first shuffle. The N! number of permutations of N elements can quickly exceed the period of a particular PRNG, and when that begins to happen, there definitely will be permutations that can't be mapped into PRNG states. When or whether repeated shuffles of the period/N! fraction of the N! permutations would eventually cover all of the permutations (including the correct, sorted order) is beyond me.

1 Like

1 Like

The millis clock ticks once every 1024 microseconds.
That's why.

1024 usecs * 250 = 256000 usecs per 8 bit ms
There's 6 too many with 256 so some values get skipped.

Thanks for your elaborate explanation.
I like the special features!
And another nice feature is that it can perform other tasks simultaneously!

I expect AI will eventually devise a previously unknown sort algorithm incomprehensible to humans.

I remember bubble sort and then a swap sort and by the time I heard about hash tables I never need a sort for whatever I was doing to pay the wolf, so I didn't dig into those.

I had a binary linked list word match routine that led to the word match method I use now but it starts from a sorted list and adding words as the list grows can take a long time inserting new links. Presorting words to add in batches does cut that down some, the links can all be merged into to one new list build. I am more centered on what I can do with the list and how fast I can match or not match entered words...
I was working on a PC version that added words in 2020 or 2021 when I kinda dropped everything. I was working on a C-Forth with member Chris Tenone when he died from COVID complications and the Orange Menace was threatening the future.. deja effing vu!

There are many ideas however sorting is always only part of the equation. The effects of cache, branch prediction, size of the array do affect the performance. Also does all data fit into memory or not? I recall implementing radix sort for merging tapes as exercise at school, when the data did (virtually) not fit into the memory.

I think most "inventions" for sorting are dedicated to data type, the influx and outflux of elements. So instead of a faster sort, the better question is how to keep data sorted.

If you have sorted an array, and you want to add 1 element, why sort the whole array again?
Or if you remove 1 element, change 1 element?
This is where hashing tables, (binary) trees and other techniques become more important than the performance of the initial sort.