Skip to content

Commit 58db283

Browse files
committed
feat: Add Timsort sorting algorithm.
1 parent e5dad3f commit 58db283

File tree

1 file changed

+177
-0
lines changed

1 file changed

+177
-0
lines changed

sorting/timsort.c

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/**
2+
* @file
3+
* @author [LJFP](https://github.com/ljfp/)
4+
* @brief [Timsort](https://en.wikipedia.org/wiki/Timsort) implementation
5+
* @details
6+
* Timsort is a hybrid stable sorting algorithm, derived from merge sort and
7+
* insertion sort, designed to perform well on many kinds of real-world data.
8+
* Worst-case time complexity is O(n log n).
9+
* Worst-case space complexity is O(n).
10+
*/
11+
#include <assert.h>
12+
#include <stdio.h>
13+
#include <stdlib.h>
14+
#include <time.h>
15+
16+
#define min(a, b) \
17+
((a) < (b) ? (a) : (b)) /* Macro to find the minimum of two numbers */
18+
19+
/**
20+
* @brief Performs insertion sort on a subarray
21+
* @param arr Array to be sorted
22+
* @param left Starting index of the subarray
23+
* @param right Ending index of the subarray
24+
*/
25+
void insertionSort(int arr[], int left, int right)
26+
{
27+
for (int i = left + 1; i <= right; i++)
28+
{
29+
int temp = arr[i];
30+
int j = i - 1;
31+
while (j >= left && arr[j] > temp)
32+
{
33+
arr[j + 1] = arr[j];
34+
j--;
35+
}
36+
arr[j + 1] = temp;
37+
}
38+
}
39+
40+
/**
41+
* @brief Merges two sorted subarrays of arr[]
42+
* @param arr The main array containing the subarrays to be merged
43+
* @param l Left index of the first subarray
44+
* @param m Ending index of the first subarray (midpoint)
45+
* @param r Right index of the second subarray
46+
*/
47+
void merge(int arr[], int l, int m, int r)
48+
{
49+
int len1 = m - l + 1;
50+
int len2 = r - m;
51+
52+
int *left = (int *)malloc(len1 * sizeof(int));
53+
int *right = (int *)malloc(len2 * sizeof(int));
54+
55+
for (int i = 0; i < len1; i++) left[i] = arr[l + i];
56+
for (int i = 0; i < len2; i++) right[i] = arr[m + 1 + i];
57+
58+
int i = 0, j = 0, k = l;
59+
60+
/* Merging the two subarrays */
61+
while (i < len1 && j < len2)
62+
{
63+
if (left[i] <= right[j])
64+
{
65+
arr[k++] = left[i++];
66+
}
67+
else
68+
{
69+
arr[k++] = right[j++];
70+
}
71+
}
72+
73+
/* Copying remaining elements of left[], if any */
74+
while (i < len1)
75+
{
76+
arr[k++] = left[i++];
77+
}
78+
79+
/* Copying remaining elements of right[], if any */
80+
while (j < len2)
81+
{
82+
arr[k++] = right[j++];
83+
}
84+
85+
free(left);
86+
free(right);
87+
}
88+
89+
/**
90+
* @brief Implementation of Timsort with specified run size
91+
* @param arr Array to be sorted
92+
* @param n Size of the array
93+
* @param run_size Size of the runs. It should be a power of 2.
94+
*/
95+
void timsort(int arr[], int n, int run_size)
96+
{
97+
/* Sort individual subarrays of size run_size */
98+
for (int i = 0; i < n; i += run_size)
99+
{
100+
insertionSort(arr, i, min((i + run_size - 1), (n - 1)));
101+
}
102+
103+
/* Start merging from size run_size */
104+
for (int size = run_size; size < n; size *= 2)
105+
{
106+
/* Pick starting point of left subarray */
107+
for (int left = 0; left < n; left += 2 * size)
108+
{
109+
/* Find ending point of left subarray */
110+
int mid = min(left + size - 1, n - 1);
111+
int right = min(left + 2 * size - 1, n - 1);
112+
113+
/* Merge subarrays arr[left...mid] & arr[mid+1...right] */
114+
if (mid < right)
115+
{
116+
merge(arr, left, mid, right);
117+
}
118+
}
119+
}
120+
}
121+
122+
/**
123+
* @brief Test function to verify the Timsort implementation.
124+
*/
125+
void test()
126+
{
127+
const int size = rand() % 500; /* Random array size between 0 and 499 */
128+
int *arr = (int *)malloc(size * sizeof(int));
129+
130+
/* Generate 'size' random numbers from -500 to 499 */
131+
for (int i = 0; i < size; i++)
132+
{
133+
arr[i] = (rand() % 1000) - 500; /* Signed random numbers */
134+
}
135+
136+
/* Test with different run sizes */
137+
for (int run_size = 16; run_size <= 64; run_size *= 2)
138+
{
139+
/* Copy the original array to preserve it for each run size */
140+
int *arr_copy = (int *)malloc(size * sizeof(int));
141+
for (int i = 0; i < size; i++)
142+
{
143+
arr_copy[i] = arr[i];
144+
}
145+
146+
timsort(arr_copy, size, run_size);
147+
148+
/* Verify that the array is sorted */
149+
for (int i = 0; i < size - 1; ++i)
150+
{
151+
assert(arr_copy[i] <= arr_copy[i + 1]);
152+
}
153+
154+
free(arr_copy);
155+
}
156+
157+
free(arr);
158+
}
159+
160+
/**
161+
* @brief Main function to test Timsort implementation
162+
* @return 0 on success
163+
*/
164+
int main()
165+
{
166+
/* Initialize random number generator */
167+
srand((unsigned int)time(NULL));
168+
169+
/* Run the test multiple times */
170+
for (int i = 0; i < 1000; i++)
171+
{
172+
test();
173+
}
174+
175+
printf("All tests passed successfully.\n");
176+
return 0;
177+
}

0 commit comments

Comments
 (0)