* 目录结构
sort/{ArrayUtil.php,Comparator.php,Shell.php}
autoload.php
index.php
* sort/Shell.php
<?php
namespace sort;
class Shell {
protected $comparator;
public function __construct(Comparator $c) {
$this->comparator = $c;
}
public function sort(array &$a) {
$N = count($a);
$h = 1;
while ($h < floor($N/3)) {
$h = 3 * $h + 1;
}
while ($h >= 1) {
for ($i = $h; $i < $N; $i++) {
for ($j = $i; $j >= $h && $this->comparator->lessThan(
$a[$j], $a[$j-$h]); $j -= $h)
ArrayUtil::exch($a, $j, $j-$h);
}
$h = floor($h/3);
}
}
}
* 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);
* 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;
}
}
* test:
index.php
<?php
include 'autoload.php';
use \sort\ArrayUtil;
use \sort\Comparator;
use \sort\Shell;
$a = [1,2,3,4,5,6];
$numcmp = function($a, $b) {return $a-$b;};
$b = ArrayUtil::isSorted($a, $numcmp);
var_dump($b); // true
ArrayUtil::exch($a, 0, count($a)-1);
$b = ArrayUtil::isSorted($a, $numcmp);
var_dump($b); // false
var_dump($b); // true
$s = ArrayUtil::some($a, function($e) {return $e % 2 === 0;});
var_dump($s); // true
$s = ArrayUtil::some($a, function($e) {return $e > 7;});
var_dump($s); // false
unset($s);
unset($a);
$s = "SHELLSHORTEXAMPLE";
$a = str_split($s);
$shell = new Shell(new Comparator(strcmp));
$shell->sort($a);
echo implode('', $a).PHP_EOL; // AEEEHHLLLMOPRSSTX
var_dump(ArrayUtil::isSorted($a, strcmp)); // bool(true)
$ php index.php
bool(true)
bool(false)
bool(false)
bool(true)
bool(false)
AEEEHHLLLMOPRSSTX
bool(true)