Skip to content
44 changes: 44 additions & 0 deletions src/ShellSort.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

namespace Src;

class ShellSort
{
/**
* @param array<int,float> $arr
* @return array<int,float>
*/
public static function sort(array $arr): array
{
$length = count($arr);
$stepSequence = $length;
do {
$stepSequence = self::stepSequence($stepSequence);
for ($i = 0; $i < $stepSequence; $i++) {
for ($j = $i+$stepSequence; $j < $length; $j += $stepSequence) {
for ($k = $j; $k >= $stepSequence; $k -= $stepSequence) {
if ($arr[$k - $stepSequence] > $arr[$k]) {
[$arr[$k], $arr[$k - $stepSequence]] = [$arr[$k - $stepSequence], $arr[$k]];
}
}
}
}
} while ($stepSequence > 1);
return $arr;
}

/**
* Returns the next step sequence based on the current lenght/step
*
* @param int $start current step sequence or array length
* @return int next lower step sequence
*/
private static function stepSequence(int $start): int
{
$next = 1;
while ($start > $new = ($next + 1) * 3) {
$next = $new;
}
return $next;
}
}
60 changes: 60 additions & 0 deletions tests/ShellSortTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use Src\ShellSort;

final class ShellSortTest extends TestCase
{
#[Test]
#[DataProvider('arrayProvider')]
public function it_should_return_the_sorted_array($arr): void
{
$this->assertEquals([1,2,3,4,5,6,7,8,9], ShellSort::sort($arr));
}

/*
* @return array
*/
public static function arrayProvider(): array
{
return [
[[1,2,3,4,5,6,7,8,9]],
[[9,8,7,6,5,4,3,2,1]],
[[1,2,3,9,8,7,6,5,4]],
[[9,8,7,1,2,3,4,5,6]],
[[9,1,8,2,7,3,6,4,5]],
[[1,9,2,8,3,7,4,6,5]],
[[6,4,1,8,3,9,2,5,7]],
];
}

#[Test]
public function it_should_sort_single_element_array(): void
{
$this->assertEquals([4], ShellSort::sort([4]));
}

#[Test]
public function test_empty_array(): void
{
$this->assertEquals([], ShellSort::sort([]));
}

#[Test]
public function it_should_sort_non_consecutive_numbers_correctly(): void
{
$this->assertEquals([2,5,6,8,9], ShellSort::sort([5,9,6,2,8]));
}

#[Test]
public function it_can_sort_array_with_1000_elements(): void
{
$random = range(1, 1000);
shuffle($random);
$this->assertEquals(range(1, 1000), ShellSort::sort($random));
}
}