Tim Sort
Tim Sort :
Author(s) : Tim Peters Date : 2002Timsort is a hybrid sorting algorithm that combines the strengths of insertion sort and merge sort. It is often used in Java's Arrays.sort() method due to its efficiency for most real-world data sets. Timsort initially partitions the input array into runs (partially sorted sub-arrays). For small runs, insertion sort is applied for its speed. When merging larger runs, a variant of merge sort is employed, optimized for already partially sorted data. This hybrid approach makes Timsort generally faster than pure insertion sort or merge sort for most data.
| Time Complexity | O(n log n) |
| Best Case | O(n) |
| Worst Case | O(n log n) |
| Space Complexity | O(n) |
| Stable | Yes |
Code Integration:
* the code might contain some bugs or may not work correctly
def timsort(arr, n):
run_size = 32 # Define a small run size
# Identify natural runs (already sorted subarrays)
for i in range(n):
if i == 0 or arr[i] > arr[i - 1]: # Start of a new run
min_run = max(run_size, i + 1) # Minimum run size (including current element)
while i + 1 < n and arr[i + 1] >= arr[i]: # Extend run if elements are increasing
i += 1
max_run = min(n - i, 2 * run_size) # Limit run size (avoid overflow)
# Minimise run size if two previous runs are large enough
if i > 0 and n - i >= min_run * 2:
# In-place merge with the previous larger run
j = i - min_run
while j < i and arr[j] > arr[i]:
arr[i + 1], arr[j] = arr[j], arr[i + 1]
i += 1
j += 1
# Timsort logic (in-place merging)
for i in range(0, n, run_size): # Loop through potential runs
end_run1 = min(i + run_size, n) # End of first potential run
# Check if next element starts a new run (avoid unnecessary merge)
if end_run1 < n and arr[end_run1] >= arr[end_run1 - 1]:
continue
# Merge current run with the next run (if it exists)
end_run2 = min(end_run1 + run_size, n)
while end_run1 < end_run2:
if arr[end_run1] <= arr[end_run2 - 1]:
end_run1 += 1
else:
temp = arr[end_run2 - 1]
j = end_run2 - 2
while j >= end_run1 and arr[j] > temp:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = temp
end_run1 += 1
end_run2 += 1
# Test array
arr = [12, 11, 13, 5, 6, 7]
timSort(arr, len(arr))
print('Sorted array is:', arr)
function timsort(arr, n) {
const run_size = 32; // Define a small run size
// Identify natural runs (already sorted subarrays)
for (let i = 0; i < n; i++) {
if (i === 0 || arr[i] > arr[i - 1]) { // Start of a new run
let min_run = Math.max(run_size, i + 1); // Minimum run size
while (i + 1 < n && arr[i + 1] >= arr[i]) { // Extend run if elements are increasing
i++;
}
const max_run = Math.min(n - i, 2 * run_size); // Limit run size (avoid overflow)
// Minimise run size if two previous runs are large enough
if (i > 0 && n - i >= min_run * 2) {
// In-place merge with the previous larger run
let j = i - min_run;
while (j < i && arr[j] > arr[i]) {
const temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
j++;
}
}
}
}
// Timsort logic (in-place merging)
for (let i = 0; i < n; i += run_size) {
const end_run1 = Math.min(i + run_size, n); // End of first potential run
// Check if next element starts a new run (avoid unnecessary merge)
if (end_run1 < n && arr[end_run1] >= arr[end_run1 - 1]) {
continue;
}
// Merge current run with the next run (if it exists)
const end_run2 = Math.min(end_run1 + run_size, n);
while (end_run1 < end_run2) {
if (arr[end_run1] <= arr[end_run2 - 1]) {
end_run1++;
} else {
const temp = arr[end_run2 - 1];
let j = end_run2 - 2;
while (j >= end_run1 && arr[j] > temp) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = temp;
end_run1++;
end_run2++;
}
}
}
}
public class Timsort {
private static final int RUN_SIZE = 32; // Define a small run size
public static void sort(int[] arr, int n) {
// Identify natural runs (already sorted subarrays)
for (int i = 0; i < n; i++) {
if (i == 0 || arr[i] > arr[i - 1]) { // Start of a new run
int minRun = Math.max(RUN_SIZE, i + 1); // Minimum run size
while (i + 1 < n && arr[i + 1] >= arr[i]) { // Extend run if increasing
i++;
}
int maxRun = Math.min(n - i, 2 * RUN_SIZE); // Limit run size (avoid overflow)
// Minimise run size if two previous runs are large enough
if (i > 0 && n - i >= minRun * 2) {
// In-place merge with the previous larger run
int j = i - minRun;
while (j < i && arr[j] > arr[i]) {
swap(arr, i, j);
i++;
j++;
}
}
}
}
// Timsort logic (in-place merging)
for (int i = 0; i < n; i += RUN_SIZE) {
int endRun1 = Math.min(i + RUN_SIZE, n); // End of first potential run
// Check if next element starts a new run (avoid unnecessary merge)
if (endRun1 < n && arr[endRun1] >= arr[endRun1 - 1]) {
continue;
}
// Merge current run with the next run (if it exists)
int endRun2 = Math.min(endRun1 + RUN_SIZE, n);
while (endRun1 < endRun2) {
if (arr[endRun1] <= arr[endRun2 - 1]) {
endRun1++;
} else {
int temp = arr[endRun2 - 1];
int j = endRun2 - 2;
while (j >= endRun1 && arr[j] > temp) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = temp;
endRun1++;
endRun2++;
}
}
}
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
package timsort
const runSize = 32 // Define a small run size
func sort(arr []int, n int) {
// Identify natural runs (already sorted subarrays)
for i := 0; i < n; i++ {
if i == 0 || arr[i] > arr[i-1] { // Start of a new run
minRun := max(runSize, i+1) // Minimum run size (including current element)
for i+1 < n && arr[i+1] >= arr[i] { // Extend run if elements are increasing
i++
}
maxRun := min(n-i, 2*runSize) // Limit run size (avoid overflow)
// Minimise run size if two previous runs are large enough
if i > 0 && n-i >= minRun*2 {
// In-place merge with the previous larger run
j := i - minRun
for j < i && arr[j] > arr[i] {
arr[i], arr[j] = arr[j], arr[i]
i++
j++
}
}
}
}
// Timsort logic (in-place merging)
for i := 0; i < n; i += runSize {
endRun1 := min(i+runSize, n) // End of first potential run
// Check if next element starts a new run (avoid unnecessary merge)
if endRun1 < n && arr[endRun1] >= arr[endRun1-1] {
continue
}
// Merge current run with the next run (if it exists)
endRun2 := min(endRun1+runSize, n)
for endRun1 < endRun2 {
if arr[endRun1] <= arr[endRun2-1] {
endRun1++
} else {
temp := arr[endRun2-1]
j := endRun2 - 2
for j >= endRun1 && arr[j] > temp {
arr[j+1] = arr[j]
j--
}
arr[j+1] = temp
endRun1++
endRun2++
}
}
}
}
#include <stdio.h>
#define RUN_SIZE 32 // Define a small run size
void swap(int *a, int *b) {
// Swap function for in-place merging
int temp = *a;
*a = *b;
*b = temp;
}
void timsort(int arr[], int n) {
// Identify natural runs (already sorted subarrays)
for (int i = 0; i < n; i++) {
if (i == 0 || arr[i] > arr[i - 1]) { // Start of a new run
int min_run = (i + 1 > RUN_SIZE) ? i + 1 : RUN_SIZE; // Minimum run size
while (i + 1 < n && arr[i + 1] >= arr[i]) { // Extend run if increasing
i++;
}
int max_run = (n - i > 2 * RUN_SIZE) ? 2 * RUN_SIZE : (n - i); // Limit run size
// Minimise run size if two previous runs are large enough
if (i > 0 && n - i >= min_run * 2) {
// In-place merge with the previous larger run
int j = i - min_run;
while (j < i && arr[j] > arr[i]) {
swap(&arr[i], &arr[j]);
i++;
j++;
}
}
}
}
// Timsort logic (in-place merging)
for (int i = 0; i < n; i += RUN_SIZE) {
int end_run1 = (i + RUN_SIZE < n) ? (i + RUN_SIZE) : n; // End of first potential run
// Check if next element starts a new run (avoid unnecessary merge)
if (end_run1 < n && arr[end_run1] >= arr[end_run1 - 1]) {
continue;
}
// Merge current run with the next run (if it exists)
int end_run2 = (end_run1 + RUN_SIZE < n) ? (end_run1 + RUN_SIZE) : n;
while (end_run1 < end_run2) {
if (arr[end_run1] <= arr[end_run2 - 1]) {
end_run1++;
} else {
int temp = arr[end_run2 - 1];
int j = end_run2 - 2;
while (j >= end_run1 && arr[j] > temp) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = temp;
end_run1++;
end_run2++;
}
}
}
}