Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions src/tim_sort.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
def insertion_sort(arr, left, right):
"""
Perform insertion sort on a subarray.

:param arr: List to be sorted
:param left: Starting index of the subarray
:param right: Ending index of the subarray
"""
for i in range(left + 1, right + 1):
key = arr[i]
j = i - 1
while j >= left and arr[j] > key:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key

def merge(arr, left, mid, right):
"""
Merge two sorted subarrays.

:param arr: List to be merged
:param left: Starting index of the first subarray
:param mid: Ending index of the first subarray
:param right: Ending index of the second subarray
"""
# Calculate lengths of two subarrays to be merged
len1 = mid - left + 1
len2 = right - mid

# Create temporary arrays
left_arr = arr[left:left + len1]
right_arr = arr[mid + 1:mid + 1 + len2]

# Initial indexes of first and second subarrays
i, j, k = 0, 0, left

# Merge the temporary arrays back into arr
while i < len1 and j < len2:
if left_arr[i] <= right_arr[j]:
arr[k] = left_arr[i]
i += 1
else:
arr[k] = right_arr[j]
j += 1
k += 1

# Copy remaining elements of left_arr, if any
while i < len1:
arr[k] = left_arr[i]
i += 1
k += 1

# Copy remaining elements of right_arr, if any
while j < len2:
arr[k] = right_arr[j]
j += 1
k += 1

def tim_sort(arr):
"""
Implement Tim Sort algorithm.

:param arr: List to be sorted
:return: Sorted list
"""
# Minimum size of a run (subarray sorted using insertion sort)
MIN_RUN = 32

# Length of the input array
n = len(arr)

# Sort individual subarrays of size RUN
for i in range(0, n, MIN_RUN):
insertion_sort(arr, i, min(i + MIN_RUN - 1, n - 1))

# Start merging from size RUN (or 32)
size = MIN_RUN
while size < n:
# Pick starting point of different subarrays of size 'size'
for start in range(0, n, size * 2):
# Find ending point of left subarray
mid = start + size - 1
# Find ending point of right subarray
end = min(start + size * 2 - 1, n - 1)

# Merge subarrays arr[start...mid] and arr[mid+1...end]
if mid < end:
merge(arr, start, mid, end)

# Double the size of subarrays to be merged
size *= 2

return arr
62 changes: 62 additions & 0 deletions tests/test_tim_sort.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import pytest
from src.tim_sort import tim_sort

def test_tim_sort_empty_list():
"""Test sorting an empty list."""
arr = []
assert tim_sort(arr) == []

def test_tim_sort_single_element():
"""Test sorting a list with a single element."""
arr = [5]
assert tim_sort(arr) == [5]

def test_tim_sort_already_sorted():
"""Test sorting a list that is already sorted."""
arr = [1, 2, 3, 4, 5]
assert tim_sort(arr) == [1, 2, 3, 4, 5]

def test_tim_sort_reverse_sorted():
"""Test sorting a list in reverse order."""
arr = [5, 4, 3, 2, 1]
assert tim_sort(arr) == [1, 2, 3, 4, 5]

def test_tim_sort_duplicate_elements():
"""Test sorting a list with duplicate elements."""
arr = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
assert tim_sort(arr) == [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]

def test_tim_sort_negative_numbers():
"""Test sorting a list with negative numbers."""
arr = [-5, 3, -2, 0, 7, -1, 10]
assert tim_sort(arr) == [-5, -2, -1, 0, 3, 7, 10]

def test_tim_sort_mixed_types():
"""Test sorting a list with different numeric types."""
arr = [5, 3.14, 2, -1, 0, 7]
assert tim_sort(arr) == [-1, 0, 2, 3.14, 5, 7]

def test_tim_sort_large_list():
"""Test sorting a large list to simulate real-world scenario."""
import random
random.seed(42) # For reproducibility
arr = [random.randint(-1000, 1000) for _ in range(1000)]
sorted_arr = tim_sort(arr.copy())
assert sorted_arr == sorted(arr)

def test_tim_sort_performance():
"""Ensure Tim Sort is reasonably performant."""
import random
import time

# Create a large list for performance testing
random.seed(42)
arr = [random.randint(-10000, 10000) for _ in range(10000)]

# Measure sorting time
start_time = time.time()
tim_sort(arr)
end_time = time.time()

# Ensure sorting takes less than 1 second
assert end_time - start_time < 1.0