3

I'm using this Javascript code to view the order in which array elements are compared when the sort method is invoked.

function log(text)
{
    document.documentElement.appendChild(document.createElement('div')).appendChild(document.createTextNode(text));
}

[5, 4, 3, 2, 1].sort(function (a, b) {
    log("comparing " + a + " and " + b);
    return a - b;
});

I'm not surprised to see that different browsers produce different outputs because of diverse implementations. What I cannot realize is why IE and Opera sometimes compare the same pair of values twice in succession. That doesn't make any sense to me. Sorting arrays looks like such a basic language feature I'm probably missing something here. Can someone explain this behavior?

Here are my test results:

IE 9 and 10

  • comparing 4 and 5
  • comparing 4 and 5
  • comparing 3 and 5
  • comparing 3 and 4
  • comparing 2 and 5
  • comparing 2 and 4
  • comparing 2 and 3
  • comparing 1 and 5
  • comparing 1 and 3
  • comparing 1 and 2

Firefox

  • comparing 5 and 4
  • comparing 5 and 3
  • comparing 4 and 3
  • comparing 2 and 1
  • comparing 5 and 1
  • comparing 3 and 1
  • comparing 3 and 2

Chrome

  • comparing 5 and 4
  • comparing 5 and 3
  • comparing 4 and 3
  • comparing 5 and 2
  • comparing 4 and 2
  • comparing 3 and 2
  • comparing 5 and 1
  • comparing 4 and 1
  • comparing 3 and 1
  • comparing 2 and 1

Opera

  • comparing 5 and 4
  • comparing 2 and 1
  • comparing 3 and 1
  • comparing 3 and 1
  • comparing 3 and 2
  • comparing 5 and 1
  • comparing 4 and 1
  • comparing 4 and 2
  • comparing 4 and 3

And the proof of concept: http://jsfiddle.net/Sd9ph/

GOTO 0
  • 42,323
  • 22
  • 125
  • 158
  • 2
    You can probably find the answer buried in the [implementation details for sort](http://stackoverflow.com/questions/234683/javascript-array-sort-implementation). – jbabey Apr 23 '13 at 12:11
  • 1
    That's depend on sort algorithm used in javascript engine implemented by the browser. – Jack Apr 23 '13 at 12:13

1 Answers1

2

We don't know the details, since their implementations are not open source.

Yet, Opera seems to use some a merge sort where the merge phase includes comparing the range boundaries (to do a more efficient concatenation instead of merging item-per-item - when possible). In the minimal case, one of the ranges has only one item in it - which will then be compared twice if it cannot just be prepended. It could use an optimisation, but it won't happen that often, so it wasn't worth it apparently.

You can check the behaviour here with three-item-arrays. Example for [3,2,1]:

3 2 1

[3][2 1] // divide

[3][2 1] // compare (and exchange)
    ^ ^
[3][1 2] // compare upper with lower boundary (would concat if possible)
  ^^
[3][1 2] // but they're overlapping, so let's merge…
 ^  ^
1 [3][2] // …by comparing smallest items from each set
   ^  ^
1 2 3

Example for [2,1,4,3], with concatenation:

2 1 4 3

[2 1][4 3] // divide

[2 1][4 3] // and sort sub-arrays
 ^ ^  ^ ^
[1 2][3 4] // compare boundaries
    ^^
1 2 3 4    // uh, we're done already!

This concatenation will make the mergesort faster for (at least partly) already-sorted arrays.

Internet Explorer in contrast does a classical insertion sort. I'd assume that it first tests whether the array is already sorted - which fails at the first comparison, 4 is not >= 5. Then it inserts 4 before 5, 3 before 5 and 4, 2 before 5 and 4 and 3, and since 1 lacks a comparison with 4 it seems it uses a kind of binary search for that.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Uh, I had only looked at Opera - sorry. Extended my answer with a detailed explanation of my theory and what IE seems to do. – Bergi Apr 23 '13 at 13:52
  • Ok, your explanation about the IE checking if the array is already sorted makes perfect sense. I still don't get the double comparison in Opera. When I perform a regular divide and conquer sorting over [5, 4, 3, 2, 1] I get comparisons in this order: (5, 4), (2, 1), (3, 1), (3, 2), (4, 1), (4, 2), (4, 3). What's this sorting algorithm in Opera called and how is it supposed to do a more efficient concatenation? – GOTO 0 Apr 23 '13 at 20:06
  • It looks like a normal [merge sort](http://en.wikipedia.org/wiki/Merge_sort) (uh, did I forgot to state that?) to me, but with an optimized merge algorithm. It starts by dividing (into [5,4][2,3,1], then the latter in [2][3,1]) and sorting them (latter first), but then it does *only* merge them item-by-item (repeatedly choosing from the smallest two items of the two sets) *if the two ranges overlap*. If they don't, they just can be concatenated - saving a lot of compare operations. – Bergi Apr 23 '13 at 21:22
  • Sorry, I just realized that comparing the boundaries only happens for the two adjacent items - fixed the answer, and included better example. – Bergi Apr 23 '13 at 21:56