#### Tim Sort

A
p
P
```def binary_search(lst, item, start, end):
if start == end:
return start if lst[start] > item else start + 1
if start > end:
return start

mid = (start + end) // 2
if lst[mid] < item:
return binary_search(lst, item, mid + 1, end)
elif lst[mid] > item:
return binary_search(lst, item, start, mid - 1)
else:
return mid

def insertion_sort(lst):
length = len(lst)

for index in range(1, length):
value = lst[index]
pos = binary_search(lst, value, 0, index - 1)
lst = lst[:pos] + [value] + lst[pos:index] + lst[index + 1 :]

return lst

def merge(left, right):
if not left:
return right

if not right:
return left

if left[0] < right[0]:
return [left[0], *merge(left[1:], right)]

return [right[0], *merge(left, right[1:])]

def tim_sort(lst):
"""
>>> tim_sort("Python")
['P', 'h', 'n', 'o', 't', 'y']
>>> tim_sort((1.1, 1, 0, -1, -1.1))
[-1.1, -1, 0, 1, 1.1]
>>> tim_sort(list(reversed(list(range(7)))))
[0, 1, 2, 3, 4, 5, 6]
>>> tim_sort([3, 2, 1]) == insertion_sort([3, 2, 1])
True
>>> tim_sort([3, 2, 1]) == sorted([3, 2, 1])
True
"""
length = len(lst)
runs, sorted_runs = [], []
new_run = [lst[0]]
sorted_array = []
i = 1
while i < length:
if lst[i] < lst[i - 1]:
runs.append(new_run)
new_run = [lst[i]]
else:
new_run.append(lst[i])
i += 1
runs.append(new_run)

for run in runs:
sorted_runs.append(insertion_sort(run))
for run in sorted_runs:
sorted_array = merge(sorted_array, run)

return sorted_array

def main():
lst = [5, 9, 10, 3, -4, 5, 178, 92, 46, -18, 0, 7]
sorted_lst = tim_sort(lst)
print(sorted_lst)

if __name__ == "__main__":
main()
```