cpython/Lib
Tim Peters bf121d6a69
GH-116554: Relax list.sort()'s notion of "descending" runs (#116578)
* GH-116554: Relax list.sort()'s notion of "descending" run

Rewrote `count_run()` so that sub-runs of equal elements no longer end a descending run. Both ascending and descending runs can have arbitrarily many sub-runs of arbitrarily many equal elements now. This is tricky, because we only use ``<`` comparisons, so checking for equality doesn't come "for free". Surprisingly, it turned out there's a very cheap (one comparison) way to determine whether an ascending run consisted of all-equal elements. That sealed the deal.

In addition, after a descending run is reversed in-place, we now go on to see whether it can be extended by an ascending run that just happens to be adjacent. This succeeds in finding at least one additional element to append about half the time, and so appears to more than repay its cost (the savings come from getting to skip a binary search, when a short run is artificially forced to length MIINRUN later, for each new element `count_run()` can add to the initial run).

While these have been in the back of my mind for years, a question on StackOverflow pushed it to action:

https://stackoverflow.com/questions/78108792/

They were wondering why it took about 4x longer to sort a list like:

[999_999, 999_999, ..., 2, 2, 1, 1, 0, 0]

than "similar" lists. Of course that runs very much faster after this patch.

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: Pieter Eendebak <pieter.eendebak@gmail.com>
2024-03-12 19:59:42 -05:00
..
__phello__
asyncio
collections
concurrent
ctypes
curses
dbm
email
encodings
ensurepip
html
http
idlelib
importlib
json
logging
multiprocessing
pathlib
pydoc_data
re
site-packages
sqlite3
sysconfig
test GH-116554: Relax list.sort()'s notion of "descending" runs (#116578) 2024-03-12 19:59:42 -05:00
tkinter
tomllib
turtledemo
unittest
urllib
venv
wsgiref
xml
xmlrpc
zipfile
zoneinfo
__future__.py
__hello__.py
_aix_support.py
_collections_abc.py
_compat_pickle.py
_compression.py
_markupbase.py
_opcode_metadata.py
_osx_support.py
_py_abc.py
_pydatetime.py
_pydecimal.py
_pyio.py
_pylong.py
_sitebuiltins.py
_strptime.py
_threading_local.py
_weakrefset.py
abc.py
antigravity.py
argparse.py
ast.py
base64.py
bdb.py
bisect.py
bz2.py
calendar.py
cmd.py
code.py
codecs.py
codeop.py
colorsys.py
compileall.py
configparser.py
contextlib.py
contextvars.py
copy.py
copyreg.py
cProfile.py
csv.py
dataclasses.py
datetime.py
decimal.py
difflib.py
dis.py
doctest.py
enum.py
filecmp.py
fileinput.py
fnmatch.py
fractions.py
ftplib.py
functools.py
genericpath.py
getopt.py
getpass.py
gettext.py
glob.py
graphlib.py
gzip.py
hashlib.py
heapq.py
hmac.py
imaplib.py
inspect.py
io.py
ipaddress.py
keyword.py
linecache.py
locale.py
lzma.py
mailbox.py
mimetypes.py
modulefinder.py
netrc.py
ntpath.py
nturl2path.py
numbers.py
opcode.py
operator.py
optparse.py
os.py
pdb.py
pickle.py
pickletools.py
pkgutil.py
platform.py
plistlib.py
poplib.py
posixpath.py
pprint.py
profile.py
pstats.py
pty.py
py_compile.py
pyclbr.py
pydoc.py
queue.py
quopri.py
random.py
reprlib.py
rlcompleter.py
runpy.py
sched.py
secrets.py
selectors.py
shelve.py
shlex.py
shutil.py
signal.py
site.py
smtplib.py
socket.py
socketserver.py
sre_compile.py
sre_constants.py
sre_parse.py
ssl.py
stat.py
statistics.py
string.py
stringprep.py
struct.py
subprocess.py
symtable.py
tabnanny.py
tarfile.py
tempfile.py
textwrap.py
this.py
threading.py
timeit.py
token.py
tokenize.py
trace.py
traceback.py
tracemalloc.py
tty.py
turtle.py
types.py
typing.py
uuid.py
warnings.py
wave.py
weakref.py
webbrowser.py
zipapp.py
zipimport.py