(no title)
tim-peters | 4 years ago
So that's a whole lot of additional complication, but it's the heart of what _really_ makes timsort shine in its "jaw dropping" cases.
Tim (of "timsort" - which was an inside joke name at the start, because I never expected anything outside of CPython would use it ;-) ).
adamgordonbell|4 years ago
tim-peters|4 years ago
The point: for inputs like your:
a = list(range(-100, 1700)) b = list(range(1400, 1800))
it would first use a variant of binary search to find where b[0] belongs in a. "Almost all of a" is consumed by that via a relatively tiny number of compares. It would similarly do a binary-ish search to find where a[-1] belongs in b. The tail end of b, from 1700 through 1799, then also never needs to be looked at again.
In the lucky case that two input lists don't overlap at all, and a[-1] <= b[0], that's enough so that a "one-pair-at-a-time" compare _never_ needs to be done. In context (the two lists are contiguous slices of an array), no pointers at all need to be copied in that case either - it deduces that the combined array slices are already in sorted order in total time O(log(len(a)) + log(len(b))), and it's done.
borski|4 years ago
barosl|4 years ago
j-pb|4 years ago
Better real world factors?
Galloping, Demaine set intersection, worst case optimal joins, they all seem to be different aspects of the same underlying principle.
So I'm very curious about the peculiarities in the sorting case.
tim-peters|4 years ago
CPython's lists are implemented as contiguous C arrays of pointers (to Python objects). Any way of grafting a tree-ish structure on top of that would be unacceptably wasteful of space and/or time. So sorting "gallops" over arrays because it's array-in, array-out.
cratermoon|4 years ago