* sort/Heap.php
<?php
/**
* Created by PhpStorm.
* User: Mch
* Date: 2018/11/4
* Time: 10:12 PM
*/
namespace sort;
class Heap {
/** @var Comparator */
protected $comparator;
public function __construct(Comparator $c) {
$this->comparator = $c;
}
private static function leftChild($i) {
return ($i<<1) + 1;
}
private function percDown(array &$a, int $i, int $n) {
for ($tmp = $a[$i]; self::leftChild($i) < $n; $i = $child) {
$child = self::leftChild($i);
if ($child !== $n - 1 && $this->comparator->greeterThan(
$a[$child+1],$a[$child])) {
$child++;
}
if ($this->comparator->lessThan($tmp, $a[$child])) {
$a[$i] = $a[$child];
} else {
break;
}
}
$a[$i] = $tmp;
}
public function sort(array &$a) {
$n = count($a);
// build heap
for ($i = $n >> 1; $i >= 0; $i--) {
self::percDown($a, $i, $n);
}
for ($i = $n-1; $i > 0; $i--) {
// delete max
ArrayUtil::exch($a, 0, $i);
self::percDown($a, 0, $i);
}
}
}
* sort/Comparator.php
<?php
namespace sort;
class Comparator {
/** @var callable */
protected $compare;
public function __construct(callable $compareFunction = null) {
if (is_null($compareFunction)) {
$this->compare = function($a, $b) {
if ($a === $b) {return 0;}
return $a > $b ? 1 : -1;
};
return;
}
$this->compare = $compareFunction;
}
/*** @return bool */
public function equal($a, $b) {
return call_user_func($this->compare, $a, $b) === 0;
}
/*** @return bool */
public function lessThan($a, $b) {
return call_user_func($this->compare, $a, $b) < 0;
}
/*** @return bool */
public function greeterThan($a, $b) {
return call_user_func($this->compare, $a, $b) > 0;
}
/*** @return bool */
public function lessThanOrEqual($a, $b) {
return $this->lessThan($a, $b) || $this->equal($a, $b);
}
/*** @return bool */
public function greeterThanOrEqual($a, $b) {
return $this->greeterThan($a, $b) || $this->equal($a, $b);
}
public function reverse() {
$compareOriginal = $this->compare;
$this->compare = function ($a, $b) use ($compareOriginal) {
return $compareOriginal($b, $a);
};
}
}
* sort/ArrayUtil.php
<?php
namespace sort;
class ArrayUtil {
public static function shuffle(array &$a) {
$m = count($a);
while ($m) {
$i = rand(0, --$m);
self::exch($a, $i, $m);
}
}
public static function exch(array &$a, $i, $j) {
if ($i === $j) {return;}
$a[$i] = $a[$i] ^ $a[$j];
$a[$j]= $a[$i] ^ $a[$j];
$a[$i] = $a[$i] ^ $a[$j];
}
public static function some(array $a, callable $c) {
for ($i = 0, $n = count($a); $i < $n; $i++)
if ($c( $a[$i] ))
return true;
return false;
}
public static function isSorted(array $a, callable $cmp) {
for ($i = 1, $n = count($a); $i < $n; $i++)
if ($cmp($a[$i], $a[$i-1]) < 0)
return false;
return true;
}
}
* autoload.php
<?php
$prefixList = ['sort', 'dp'];
array_walk($prefixList, function($prefix) {
spl_autoload_register(function($class) use ($prefix) {
$base_dir = __DIR__ . DIRECTORY_SEPARATOR. str_replace('\\', '/', $prefix);
$len = strlen($prefix);
if (strncmp($prefix, $class, $len) !== 0) {
return;
}
$relative_class = substr($class, $len);
$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
if (file_exists($file)) {
require $file;
}
});
}, null);
<?php
// index.php
include 'autoload.php';
use sort\Heap;
use sort\Comparator;
use sort\ArrayUtil;
$s = "HEAPSORTEXAMPLE";
$a = str_split($s);
$heap = new Heap(new Comparator(strcmp));
$heap->sort($a);
echo implode('', $a).PHP_EOL;
var_dump(ArrayUtil::isSorted($a, strcmp)); // bool(true)
* test:
php index.php
AAEEEHLMOPPRSTX
bool(true)