Короче, галопом является причина. Вот почему мы сначала его не видели, потому что я думал, что gallop_
{left
, right
} вызывается только из merge
_ {lo
, hi
}. Но это не правда. gallop_
... также вызываются из merge_at
, до вызова merge
_ {lo
, hi
}, чтобы найти "С чего начинается b в a?" и "Где кончается б?" Эти вызовы (и последующий код) изменяют ssb
(и его длину nb
), а также ssa
и его длину na
, так что выполняется инвариант в заголовке.
То есть, дело в том, что A и B являются , а не"смежными трассами в стеке выполнения", как было найдено в исходном списке для сортировки. Перед вызовом merge
_ {lo
, hi
} они обрезаются, так что условие в заголовке выполняется. То есть до слияния A с B элементы B, превышающие последний элемент A, явно не учитываются. Другими словами, «Должно также быть, что ssa.keys[na-1]
принадлежит в конце слияния», верно не из-за какого-то особого свойства ssa.keys[na-1]
, а потому, что мы определили «конец слияния» таким образом. : -)
Это также означает, что когда вы внедряете Timsort самостоятельно и не учитываете скачки, вы также должны не учитывать эту оптимизацию, о которой здесь говорится, иначе код не будет работать правильно.