Implement more sorting algorithms

This commit is contained in:
Dennis Eichhorn 2019-08-17 22:33:09 +02:00
parent 7b1cf0e660
commit 047d8c3028
17 changed files with 417 additions and 2 deletions

View File

@ -0,0 +1,63 @@
<?php
/**
* Orange Management
*
* PHP Version 7.4
*
* @package phpOMS\Algorithm\Sort;
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\Algorithm\Sort;
/**
* BitonicSort class.
*
* @package phpOMS\Algorithm\Sort;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*/
class BitonicSort implements SortInterface
{
public static function sort(array $list, int $order = SortOrder::ASC) : array
{
$n = \count($list);
if ($n < 2) {
return $list;
}
$first = self::sort(\array_slice($list, 0, $n / 2), SortOrder::ASC);
$second = self::sort(\array_slice($list, $n / 2), SortOrder::DESC);
return self::merge(\array_merge($first, $second), $order);
}
public static function merge(array $list, int $order) : array
{
$n = \count($list);
if ($n === 1) {
return $list;
}
$dist = $n / 2;
for ($i = 0; $i < $dist; ++$i) {
if ($list[$i]->compare($list[$i + $dist], $order)) {
$old = $list[$i];
$list[$i] = $list[$i + $dist];
$list[$i + $dist] = $old;
}
}
$first = self::merge(\array_slice($list, 0, $n / 2), $order);
$second = self::merge(\array_slice($list, $n / 2), $order);
return \array_merge($first, $second);
}
}

View File

@ -28,6 +28,10 @@ class BubbleSort implements SortInterface
{ {
$n = \count($list); $n = \count($list);
if ($n < 2) {
return $list;
}
do { do {
$newN = 0; $newN = 0;

View File

@ -0,0 +1,43 @@
<?php
/**
* Orange Management
*
* PHP Version 7.4
*
* @package phpOMS\Algorithm\Sort;
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\Algorithm\Sort;
/**
* Bucketsort class.
*
* @package phpOMS\Algorithm\Sort;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*/
class BucketSort
{
public static function sort(array $list, int $bucketCount, string $algo = InsertionSort::class, int $order = SortOrder::ASC) : array
{
$buckets = [];
$M = $list[0]::max($list);
foreach ($list as $element) {
$buckets[(int) \floor(($bucketCount - 1) * $element->getValue() / $M)][] = $element;
}
$sorted = [];
foreach ($buckets as $bucket) {
$sorted[] = $algo::sort($bucket, SortOrder::ASC);
}
return $order === SortOrder::ASC ? \array_merge(...$sorted) : \array_reverse(\array_merge(...$sorted), false);
}
}

View File

@ -29,6 +29,10 @@ class CocktailShakerSort implements SortInterface
$start = 0; $start = 0;
$end = \count($list) - 1; $end = \count($list) - 1;
if ($end < 1) {
return $list;
}
while ($start <= $end) { while ($start <= $end) {
$newStart = $end; $newStart = $end;
$newEnd = $start; $newEnd = $start;

View File

@ -31,6 +31,10 @@ class CombSort implements SortInterface
$gap = $n; $gap = $n;
$shrink = 1.3; $shrink = 1.3;
if ($n < 2) {
return $list;
}
while (!$sorted) { while (!$sorted) {
$gap = (int) \floor($gap / $shrink); $gap = (int) \floor($gap / $shrink);

View File

@ -0,0 +1,82 @@
<?php
/**
* Orange Management
*
* PHP Version 7.4
*
* @package phpOMS\Algorithm\Sort;
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\Algorithm\Sort;
/**
* CycleSort class.
*
* @package phpOMS\Algorithm\Sort;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*/
class CycleSort implements SortInterface
{
public static function sort(array $list, int $order = SortOrder::ASC) : array
{
$writes = 0;
$n = \count($list);
if ($n < 2) {
return $list;
}
for ($start = 0; $start < \count($list) - 1; ++$start) {
$item = $list[$start];
$pos = $start;
$length0 = \count($list);
for ($i = $start + 1; $i < $length0; ++$i) {
if ($list[$i]->getValue() < $item->getValue()) {
++$pos;
}
}
if ($pos === $start) {
continue;
}
while ($item->getValue() === $list[$pos]->getValue()) {
++$pos;
}
$old = $list[$pos];
$list[$pos] = $item;
$item = $old;
++$writes;
while ($pos !== $start) {
$pos = $start;
$length1 = \count($list);
for ($i = $start + 1; $i < $length1; ++$i) {
if ($list[$i]->getValue() < $item->getValue()) {
++$pos;
}
}
while ($item->getValue() === $list[$pos]->getValue()) {
++$pos;
}
$old = $list[$pos];
$list[$pos] = $item;
$item = $old;
++$writes;
}
}
return $order === SortOrder::ASC ? $list : \array_reverse($list, false);;
}
}

View File

@ -28,6 +28,10 @@ class GnomeSort implements SortInterface
{ {
$n = \count($list); $n = \count($list);
if ($n < 2) {
return $list;
}
for ($i = 1; $i < $n; ++$i) { for ($i = 1; $i < $n; ++$i) {
$j = $i; $j = $i;

View File

@ -29,6 +29,10 @@ class OddEvenSort implements SortInterface
$sorted = false; $sorted = false;
$n = \count($list); $n = \count($list);
if ($n < 2) {
return $list;
}
while (!$sorted) { while (!$sorted) {
$sorted = true; $sorted = true;

View File

@ -28,6 +28,10 @@ class SelectionSort implements SortInterface
{ {
$n = \count($list); $n = \count($list);
if ($n < 2) {
return $list;
}
for ($i = 0; $i < $n - 1; ++$i) { for ($i = 0; $i < $n - 1; ++$i) {
$min = $i; $min = $i;

View File

@ -25,4 +25,10 @@ namespace phpOMS\Algorithm\Sort;
interface SortableInterface interface SortableInterface
{ {
public function compare(self $obj, int $order = SortOrder::ASC) : bool; public function compare(self $obj, int $order = SortOrder::ASC) : bool;
public function getValue();
public static function max(array $list);
public static function min(array $list);
} }

View File

@ -307,8 +307,9 @@ class Matrix implements \ArrayAccess, \Iterator
for ($i = 0; $i < $nDim; ++$i) { for ($i = 0; $i < $nDim; ++$i) {
$j; $j;
for ($j = 0; $j < $mDim; ++$j) { for ($j = 0; $j < $mDim; ++$j) {
if (!$selected[$j] && \abs($matrix[$j][$i]) > 0.0001) if (!$selected[$j] && \abs($matrix[$j][$i]) > 0.0001) {
break; break;
}
} }
if ($j === $mDim) { if ($j === $mDim) {
@ -321,8 +322,9 @@ class Matrix implements \ArrayAccess, \Iterator
for ($k = 0; $k < $mDim; ++$k) { for ($k = 0; $k < $mDim; ++$k) {
if ($k !== $j && \abs($matrix[$k][$i]) > 0.0001) { if ($k !== $j && \abs($matrix[$k][$i]) > 0.0001) {
for ($p = $i + 1; $p < $nDim; ++$p) for ($p = $i + 1; $p < $nDim; ++$p) {
$matrix[$k][$p] -= $matrix[$j][$p] * $matrix[$k][$i]; $matrix[$k][$p] -= $matrix[$j][$p] * $matrix[$k][$i];
}
} }
} }
} }

View File

@ -0,0 +1,56 @@
<?php
/**
* Orange Management
*
* PHP Version 7.4
*
* @package tests
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\tests\Algorithm\Sort;
use phpOMS\Algorithm\Sort\BitonicSort;
use phpOMS\Algorithm\Sort\SortOrder;
require_once __DIR__ . '/../../Autoloader.php';
/**
* @testdox phpOMS\tests\Algorithm\Sort: Bitonic sort test
*
* @internal
*/
class BitonicSortTest extends \PHPUnit\Framework\TestCase
{
protected $list = [];
protected function setUp() : void
{
$this->list = [
new NumericElement(5),
new NumericElement(1),
new NumericElement(4),
new NumericElement(2),
];
}
public function testSortASC() : void
{
$newList = BitonicSort::sort($this->list);
self::assertEquals(
[1, 2, 4, 5], [$newList[0]->value, $newList[1]->value, $newList[2]->value, $newList[3]->value]
);
}
public function testSortDESC() : void
{
$newList = BitonicSort::sort($this->list, SortOrder::DESC);
self::assertEquals(
[5, 4, 2, 1], [$newList[0]->value, $newList[1]->value, $newList[2]->value, $newList[3]->value]
);
}
}

View File

@ -0,0 +1,57 @@
<?php
/**
* Orange Management
*
* PHP Version 7.4
*
* @package tests
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\tests\Algorithm\Sort;
use phpOMS\Algorithm\Sort\BucketSort;
use phpOMS\Algorithm\Sort\SortOrder;
require_once __DIR__ . '/../../Autoloader.php';
/**
* @testdox phpOMS\tests\Algorithm\Sort: Bucket sort test
*
* @internal
*/
class BucketSortTest extends \PHPUnit\Framework\TestCase
{
protected $list = [];
protected function setUp() : void
{
$this->list = [
new NumericElement(5),
new NumericElement(1),
new NumericElement(4),
new NumericElement(2),
new NumericElement(8),
];
}
public function testSortASC() : void
{
$newList = BucketSort::sort($this->list, 2, \phpOMS\Algorithm\Sort\SelectionSort::class);
self::assertEquals(
[1, 2, 4, 5, 8], [$newList[0]->value, $newList[1]->value, $newList[2]->value, $newList[3]->value, $newList[4]->value,]
);
}
public function testSortDESC() : void
{
$newList = BucketSort::sort($this->list, 2, \phpOMS\Algorithm\Sort\SelectionSort::class, SortOrder::DESC);
self::assertEquals(
[8, 5, 4, 2, 1], [$newList[0]->value, $newList[1]->value, $newList[2]->value, $newList[3]->value, $newList[4]->value,]
);
}
}

View File

@ -0,0 +1,57 @@
<?php
/**
* Orange Management
*
* PHP Version 7.4
*
* @package tests
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\tests\Algorithm\Sort;
use phpOMS\Algorithm\Sort\CycleSort;
use phpOMS\Algorithm\Sort\SortOrder;
require_once __DIR__ . '/../../Autoloader.php';
/**
* @testdox phpOMS\tests\Algorithm\Sort: Cycle sort test
*
* @internal
*/
class CycleSortTest extends \PHPUnit\Framework\TestCase
{
protected $list = [];
protected function setUp() : void
{
$this->list = [
new NumericElement(5),
new NumericElement(1),
new NumericElement(4),
new NumericElement(2),
new NumericElement(8),
];
}
public function testSortASC() : void
{
$newList = CycleSort::sort($this->list);
self::assertEquals(
[1, 2, 4, 5, 8], [$newList[0]->value, $newList[1]->value, $newList[2]->value, $newList[3]->value, $newList[4]->value,]
);
}
public function testSortDESC() : void
{
$newList = CycleSort::sort($this->list, SortOrder::DESC);
self::assertEquals(
[8, 5, 4, 2, 1], [$newList[0]->value, $newList[1]->value, $newList[2]->value, $newList[3]->value, $newList[4]->value,]
);
}
}

View File

@ -32,4 +32,29 @@ class NumericElement implements SortableInterface
{ {
return $order === SortOrder::ASC ? $this->value > $obj->value : $this->value < $obj->value; return $order === SortOrder::ASC ? $this->value > $obj->value : $this->value < $obj->value;
} }
public function getValue()
{
return $this->value;
}
public static function max(array $list)
{
$values = [];
foreach ($list as $element) {
$values[] = $element->value;
}
return \max($values);
}
public static function min(array $list)
{
$values = [];
foreach ($list as $element) {
$values[] = $element->value;
}
return \min($values);
}
} }