Like Timsort, smoothsort is designed to cope well with partially sorted data. The image below was generated using the same sequence as the one used for Timsort.
# Possibly replace with a generator that produces Leonardo numbers?
# That would be of limited utility since this is all of them up to 31 bits.
LP = [ 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973,
3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785,
392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155,
11405773, 18454929, 29860703, 48315633, 78176337, 126491971,
204668309, 331160281, 535828591, 866988873 ]
# Solution for determining number of trailing zeroes of a number's binary representation.
# Taken from http://www.0xe3.com/text/ntz/ComputingTrailingZerosHOWTO.html
# I don't much like the magic numbers, but they really are magic.
MultiplyDeBruijnBitPosition = [ 0, 1, 28, 2, 29, 14, 24, 3,
30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7,
26, 12, 18, 6, 11, 5, 10, 9]
def trailingzeroes(v):
return MultiplyDeBruijnBitPosition[(((v & -v) * 0x077CB531L) >> 27) & 0b11111]
def sift(lst, pshift, head):
while pshift > 1:
rt = head - 1
lf = head - 1 - LP[pshift - 2]
if lst[head] >= lst[lf] and lst[head] >= lst[rt]:
break
if lst[lf] >= lst[rt]:
lst[head], lst[lf] = lst[lf], lst[head]
head = lf
pshift -= 1
else:
lst[head], lst[rt] = lst[rt], lst[head]
head = rt
pshift -= 2
lst.log()
def trinkle(lst, p, pshift, head, trusty):
while p != 1:
stepson = head - LP[pshift]
if lst[stepson] <= lst[head]:
break
if not trusty and pshift > 1:
rt = head - 1
lf = head - 1 - LP[pshift - 2]
if lst[rt] >= lst[stepson] or lst[lf] >= lst[stepson]:
break
lst[head], lst[stepson] = lst[stepson], lst[head]
lst.log()
head = stepson
trail = trailingzeroes(p & ~1)
p >>= trail
pshift += trail
trusty = False
if not trusty:
sift(lst, pshift, head)
def smoothsort(lst):
p = 1
pshift = 1
head = 0
while head < len(lst) - 1:
if (p & 3) == 3:
sift(lst, pshift, head)
p >>= 2
pshift += 2
else:
if LP[pshift - 1] >= len(lst) - 1 - head:
trinkle(lst, p, pshift, head, False)
else:
sift(lst, pshift, head)
if pshift == 1:
p <<= 1
pshift -= 1
else:
p <<= pshift - 1
pshift = 1
p |= 1
head += 1
trinkle(lst, p, pshift, head, False)
while pshift != 1 or p != 1:
if pshift <= 1:
trail = trailingzeroes(p & ~1)
p >>= trail
pshift += trail
else:
p <<= 2
p ^= 7
pshift -= 2
trinkle(lst, p >> 1, pshift + 1, head - LP[pshift] - 1, True)
trinkle(lst, p, pshift, head - 1, True)
head -= 1
List order is sampled for visualisation whenever lst.log() is called.
Copyright 2010 Aldo Cortesi