Javascript – A "slow sort": The first wrong pair is exchanged repeatedly

There are some terms that can be used to rate code. accuracy, efficiency, standby, reuse testability and few others lens measurable metrics come to mind.

Efficiency is not really a problem here, and due to the simplicity of the algorithm, this is not true. However, it was difficult to verify that the code is correct because it is almost unreadable. It is also not reusable at all, since the sorting method is embedded inline and therefore not testable.

Let's review the code in detail for this little overview.

The outer one while The loop is only terminated if srcPos == arrLen - 1, This can only happen if srcPos will not be set 0which happens only if two elements were out of order. So if we have srcPos == arrLen - 1all elements are less than or equal to their predecessors and the array is sorted.

This was a reverse goal. Although it's already slow, I mistakenly read the code by mistake (see next section) and read:

...
var srcPos = 0, dstPos, tmp; // declare variables
while (srcPos <arrLen-1) {
dstPos = srcPos + 1;
while (dstPosarr[dstPos]{tmp = arr[srcPos]arr[srcPos]= arr[dstPos]arr[dstPos]= tmp; srcPos = 0; break}
// if (arr[srcPos]> arr[dstPos]{arr[srcPos]^ = arr[dstPos]arr[dstPos]^ = arr[srcPos]arr[srcPos]^ = arr[dstPos]srcPos = 0; break}
// if (arr[srcPos]> arr[dstPos]{arr[srcPos]+ = arr[dstPos]arr[dstPos]= arr[srcPos]-arr[srcPos]arr[srcPos]+ = arr[dstPos]srcPos = 0; break}

dstPos ++;
}
srcPos ++; // Whoops!
}
...

This is even worse as we receive many unnecessary comparisons. See "But that can be made worse".

It's getting slow …

Your code will be restarted at each inversion and ends with $ mathcal O (n ^ 3) $, That's bad, but it gets worse.

But that can be made worse

Just increase src just in the outer while, Here is the analysis for the case:
The worst runtime we can get concerns an inverse array, e.g. [5,4,3,2,1]:

[5,4,3,2,1]
[4,5,3,2,1]
[3,5,4,2,1]
[2,5,4,3,1]
[1,5,4,3,2]



...

To the $ n $ Elements we need $ 1 $ Comparison to move the largest element to the second position $ 2 $ Elements to move the second largest to the third, and so on. In summary, we have $$ 1 + 2 + lpoints + (n-2) + (n-1) = frac {n (n-1)} {2} $$ Compare to bring the smallest value to the front. In contrast to bubble sorting we are always reset srcPos to zero. Therefore, the second smallest value does not take less time to get to the front:

[1,4,5,3,2]    - 4 comparisons for 1, 1 comparison for 5-4
[1,3,5,4,2] - 4 comparisons for 1, 2 comparisons for 4-5, 4-3
[1,2,5,4,3] - 4 comparisons for 1, 3 comparisons for 3-5, 3-4, 3-2

Although we should only be able to look at the subarray at index one, we should always I have the first 4 comparisons. So for the second element we have

$$ ((n-1) + 1) + ((n-1) +2) + l points + ((n-1) + (n-3)) + ((n-1) + (n- 2)))
= (n-1) (n-2) + frac {(n-1) (n-2)} {2} $$

Comparisons. For the rest it is similar:

[1,2,5,4,3]
[1,2,4,5,3]    - 4 comparisons for 1, 3 comparisons 2, 1 comparison for 5-4
[1,2,3,5,4] - 4 comparisons for 1, 3 comparisons 2, 2 comparison for 4-5

4-3

When we have completed the introduction, we get

$$ sum_ {i = 0} ^ n frac {(n-i) (n-i-1)} {2} + (n-i-1) sum_ {j = 1} ^ i (n-j) $$
that is inefficient enough. Good work there :).

legibility Really suffers because the swap logic is in a single line. In addition, there are several values ​​with short names that do not refer to your algorithm at all.

Also, we can not use sorting outside of this snippet. That prevents

  • Sort more than one array
  • custom sorting (eg vice versa, lexicographical, etc.)
  • test

So let's do a function first:

Function slowSort (arr) {
var src = 0;
var least;
var tmp;

while (src <arr.length - 1) {
dest = src + 1;
while (at least < arr.length) {
            if(arr[src] > arr[dest]) {
temp = arr[dest];
arr[dest] = arr[src];
arr[src] = Temp;
src = 0;
break;
}
least ++;
src ++; // Put this on the outside to make it worse, but
// Remember to set `src = -1` instead.
}
}
}

This is much easier to read. We can now too

  • sort several times
  • Get improvements / speed regressions for each call page
  • add additional comparison methods, such as

    Function slowSort (arr, comp) {...}
    
  • exam the function

Always try to make your code reusable, verifiable and readable.