Perl Program to Implement Tim Sort

Perl Program to Implement Tim Sort

Tim Sort is a modern sorting algorithm that was designed to work well on real-world data. It is smart because it takes advantage of patterns that already exist in data, such as small sorted sections. Instead of treating every dataset the same way, Tim Sort looks at the data and adapts its behavior. This makes it very fast and reliable in practice, which is why it is used in popular languages like Python and Java for their built-in sorting functions.

Pluralsight Logo
Accelerate your tech career
with hands-on learning.
Whether you're a tech newbie or a total pro,
get the skills and confidence to land your next move.
Start 10-Day Free Trial

For beginners learning Perl, understanding Tim Sort is a great way to see how simple ideas like insertion sort and merge sort can be combined into something powerful. Even if you never write Tim Sort from scratch in real projects, studying it helps you think like an algorithm designer. In this article, we will walk through several Perl programs that show how Tim Sort works step by step, using plain English and full runnable examples.

Program 1: Basic Tim Sort using insertion sort and merge sort

This first program shows a simple and beginner-friendly version of Tim Sort in Perl. It focuses on the main idea of splitting the array into small parts, sorting those parts, and then merging them together. The data is predefined so you can run it immediately.

use strict;
use warnings;

my @arr = (64, 34, 25, 12, 22, 11, 90);
my $RUN = 32;

sub insertion_sort {

    my ($arr, $left, $right) = @_;

    for my $i ($left + 1 .. $right) {

        my $key = $arr->[$i];
        my $j = $i - 1;

        while ($j >= $left && $arr->[$j] > $key) {
            $arr->[$j + 1] = $arr->[$j];
            $j--;
        }

        $arr->[$j + 1] = $key;

    }

}

sub merge {

    my ($arr, $l, $m, $r) = @_;
    my @left  = @$arr[$l .. $m];
    my @right = @$arr[$m + 1 .. $r];

    my ($i, $j, $k) = (0, 0, $l);

    while ($i < @left && $j < @right) {

        if ($left[$i] <= $right[$j]) {
            $arr->[$k++] = $left[$i++];
        } else {
            $arr->[$k++] = $right[$j++];
        }

    }

    $arr->[$k++] = $left[$i++] while $i < @left;
    $arr->[$k++] = $right[$j++] while $j < @right;

}

my $n = scalar @arr;

for (my $i = 0; $i < $n; $i += $RUN) {
    insertion_sort(\@arr, $i, ($i + $RUN - 1 < $n - 1) ? $i + $RUN - 1 : $n - 1);
}

for (my $size = $RUN; $size < $n; $size *= 2) {

    for (my $left = 0; $left < $n; $left += 2 * $size) {

        my $mid = $left + $size - 1;
        my $right = ($left + 2 * $size - 1 < $n - 1) ? $left + 2 * $size - 1 : $n - 1;
        merge(\@arr, $left, $mid, $right) if $mid < $right;

    }

}

print "Sorted array: @arr\n";

This program works by first sorting small chunks of the array using insertion sort. Once those chunks are sorted, it merges them together using merge sort logic. Beginners can understand this by thinking of it as sorting small piles first and then carefully combining them into one big sorted pile.

Program 2: Tim Sort with smaller runs for learning

This version uses a smaller run size to make it easier to see how the algorithm behaves. It is not optimized for speed but is great for learning and experimenting.

use strict;
use warnings;

my @arr = (5, 21, 7, 23, 19, 10, 3);
my $RUN = 4;

sub insertion_sort {

    my ($arr, $l, $r) = @_;

    for my $i ($l + 1 .. $r) {

        my $temp = $arr->[$i];
        my $j = $i - 1;

        while ($j >= $l && $arr->[$j] > $temp) {
            $arr->[$j + 1] = $arr->[$j];
            $j--;
        }

        $arr->[$j + 1] = $temp;

    }

}

sub merge {

    my ($arr, $l, $m, $r) = @_;
    my @temp = ();
    my ($i, $j) = ($l, $m + 1);

    while ($i <= $m && $j <= $r) {

        if ($arr->[$i] <= $arr->[$j]) {
            push @temp, $arr->[$i++];
        } else {
            push @temp, $arr->[$j++];
        }

    }

    push @temp, $arr->[$i++] while $i <= $m;
    push @temp, $arr->[$j++] while $j <= $r;

    @$arr[$l .. $r] = @temp;

}

my $n = @arr;

for (my $i = 0; $i < $n; $i += $RUN) {
    insertion_sort(\@arr, $i, ($i + $RUN - 1 < $n - 1) ? $i + $RUN - 1 : $n - 1);
}

for (my $size = $RUN; $size < $n; $size *= 2) {

    for (my $left = 0; $left < $n; $left += 2 * $size) {

        my $mid = $left + $size - 1;
        my $right = ($left + 2 * $size - 1 < $n - 1) ? $left + 2 * $size - 1 : $n - 1;
        merge(\@arr, $left, $mid, $right) if $mid < $right;

    }

}

print "Sorted array: @arr\n";

Here, the smaller run size helps beginners clearly see how small groups are sorted first. This makes Tim Sort feel less mysterious and more like a natural extension of simpler sorting techniques.

Program 3: Tim Sort using clearer function separation

This program separates responsibilities more clearly, which can help beginners read and understand the code. Each function has a single job.

use strict;
use warnings;

my @arr = (8, 4, 2, 9, 5, 1, 7);
my $RUN = 3;

sub sort_runs {

    my ($arr, $run) = @_;
    my $n = @$arr;

    for (my $i = 0; $i < $n; $i += $run) {
        insertion_sort($arr, $i, ($i + $run - 1 < $n - 1) ? $i + $run - 1 : $n - 1);
    }

}

sub insertion_sort {

    my ($arr, $l, $r) = @_;

    for my $i ($l + 1 .. $r) {

        my $key = $arr->[$i];
        my $j = $i - 1;

        while ($j >= $l && $arr->[$j] > $key) {
            $arr->[$j + 1] = $arr->[$j];
            $j--;
        }

        $arr->[$j + 1] = $key;

    }

}

sub merge_runs {

    my ($arr, $run) = @_;
    my $n = @$arr;

    for (my $size = $run; $size < $n; $size *= 2) {

        for (my $left = 0; $left < $n; $left += 2 * $size) {

            my $mid = $left + $size - 1;
            my $right = ($left + 2 * $size - 1 < $n - 1) ? $left + 2 * $size - 1 : $n - 1;
            merge($arr, $left, $mid, $right) if $mid < $right;

        }

    }

}

sub merge {

    my ($arr, $l, $m, $r) = @_;
    my @left  = @$arr[$l .. $m];
    my @right = @$arr[$m + 1 .. $r];
    my ($i, $j, $k) = (0, 0, $l);

    while ($i < @left && $j < @right) {

        if ($left[$i] <= $right[$j]) {
            $arr->[$k++] = $left[$i++];
        } else {
            $arr->[$k++] = $right[$j++];
        }

    }

    $arr->[$k++] = $left[$i++] while $i < @left;
    $arr->[$k++] = $right[$j++] while $j < @right;

}

sort_runs(\@arr, $RUN);
merge_runs(\@arr, $RUN);

print "Sorted array: @arr\n";

This version is useful because it reads more like a story. First, runs are sorted, then runs are merged. Beginners can follow the flow step by step and even reuse these functions in other programs.

Program 4: Tim Sort with comments for learning

This program adds clarity through structure and naming. It is ideal for learners who want to study and modify the code.

use strict;
use warnings;

# Array to sort
my @arr = (15, 3, 27, 8, 12, 6);

# Size of small chunks for insertion sort
my $RUN = 4;

# Main TimSort function
sub tim_sort {

    my ($arr) = @_;
    my $n = @$arr;

    # Step 1: Sort small chunks with insertion sort
    for (my $i = 0; $i < $n; $i += $RUN) {

        # Make sure we don’t go past the end of the array
        my $end = ($i + $RUN - 1 < $n - 1) ? $i + $RUN - 1 : $n - 1;
        insertion_sort($arr, $i, $end);

    }

    # Step 2: Merge sorted chunks
    for (my $size = $RUN; $size < $n; $size *= 2) {

        for (my $left = 0; $left < $n; $left += 2 * $size) {

            my $mid = $left + $size - 1;
            my $right = ($left + 2 * $size - 1 < $n - 1) ? $left + 2 * $size - 1 : $n - 1;

            # Only merge if mid is before right
            merge($arr, $left, $mid, $right) if $mid < $right;

        }

    }

}

# Insertion sort for a subarray from index l to r
sub insertion_sort {

    my ($arr, $l, $r) = @_;

    for my $i ($l + 1 .. $r) {

        my $value = $arr->[$i];
        my $j = $i - 1;

        # Shift larger elements to the right
        while ($j >= $l && $arr->[$j] > $value) {
            $arr->[$j + 1] = $arr->[$j];
            $j--;
        }

        # Place current element in correct position
        $arr->[$j + 1] = $value;

    }

}

# Merge function: sort the combined slice
# Note: This is a simple approach using Perl's sort
sub merge {

    my ($arr, $l, $m, $r) = @_;
    my @temp = sort { $a <=> $b } (@$arr[$l .. $r]);
    @$arr[$l .. $r] = @temp;

}

# Call TimSort on the array
tim_sort(\@arr);

# Print the sorted array
print "Sorted array: @arr\n";

This approach simplifies merging by using Perl’s built-in sort for small sections. While not a pure Tim Sort merge, it helps beginners focus on the main idea without getting lost in details.

Program 5: Tim Sort handling negative and floating-point numbers

Tim Sort naturally works with negative and floating-point numbers when comparisons are done correctly. This final program shows that clearly.

use strict;
use warnings;

my @arr = (3.5, -2.1, 4.0, 1.2, -7.8, 0.0);
my $RUN = 3;

sub insertion_sort {

    my ($arr, $l, $r) = @_;

    for my $i ($l + 1 .. $r) {

        my $key = $arr->[$i];
        my $j = $i - 1;

        while ($j >= $l && $arr->[$j] > $key) {
            $arr->[$j + 1] = $arr->[$j];
            $j--;
        }

        $arr->[$j + 1] = $key;

    }

}

sub merge {

    my ($arr, $l, $m, $r) = @_;
    my @left  = @$arr[$l .. $m];
    my @right = @$arr[$m + 1 .. $r];
    my ($i, $j, $k) = (0, 0, $l);

    while ($i < @left && $j < @right) {

        if ($left[$i] <= $right[$j]) {
            $arr->[$k++] = $left[$i++];
        } else {
            $arr->[$k++] = $right[$j++];
        }

    }

    $arr->[$k++] = $left[$i++] while $i < @left;
    $arr->[$k++] = $right[$j++] while $j < @right;

}

my $n = @arr;

for (my $i = 0; $i < $n; $i += $RUN) {
    insertion_sort(\@arr, $i, ($i + $RUN - 1 < $n - 1) ? $i + $RUN - 1 : $n - 1);
}

for (my $size = $RUN; $size < $n; $size *= 2) {

    for (my $left = 0; $left < $n; $left += 2 * $size) {

        my $mid = $left + $size - 1;
        my $right = ($left + 2 * $size - 1 < $n - 1) ? $left + 2 * $size - 1 : $n - 1;

        merge(\@arr, $left, $mid, $right) if $mid < $right;

    }

}

print "Sorted array: @arr\n";

This program proves that Tim Sort can handle real-world data, including negative values and decimals. Beginners can safely use the same logic for many types of numeric data.

Frequently Asked Questions (FAQ)

This section answers common beginner questions about Tim Sort in Perl in a simple and practical way.

Q1. What makes Tim Sort different from other sorting algorithms?
Tim Sort is adaptive, which means it takes advantage of existing order in data. This makes it faster on real-world datasets compared to many traditional algorithms.

Q2. Is Tim Sort hard to learn for beginners?
Tim Sort may look complex at first, but when broken into insertion sort and merge sort, it becomes much easier to understand. Learning it step by step helps a lot.

Q3. Do I need to implement Tim Sort in real Perl projects?
In most real projects, Perl’s built-in sort is enough. Implementing Tim Sort is mainly useful for learning algorithms and improving problem-solving skills.

Q4. Can Tim Sort handle duplicate values?
Yes, Tim Sort handles duplicate values naturally and keeps the sorting stable, meaning equal elements keep their original order.

Q5. Does Tim Sort work with floating-point numbers?
Yes, as long as numeric comparisons are used, Tim Sort works correctly with floating-point and negative numbers.

Conclusion

Tim Sort is a powerful and practical sorting algorithm that combines simple ideas into an efficient solution. By studying how insertion sort and merge sort work together in Perl, beginners can gain a deeper understanding of how real-world sorting systems are designed. The programs in this article show different ways to implement Tim Sort, from basic versions to ones that handle more complex data.

The best way to learn is by running these Perl programs, changing the data, and experimenting with the code. With practice, Tim Sort will no longer feel complex, and you will become more confident in understanding and writing efficient algorithms in Perl.

Scroll to Top