diff --git a/src/ShellSort.php b/src/ShellSort.php new file mode 100644 index 0000000..97bcbf6 --- /dev/null +++ b/src/ShellSort.php @@ -0,0 +1,44 @@ + $arr + * @return array + */ + 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; + } +} diff --git a/tests/ShellSortTest.php b/tests/ShellSortTest.php new file mode 100644 index 0000000..3beba15 --- /dev/null +++ b/tests/ShellSortTest.php @@ -0,0 +1,60 @@ +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)); + } +}