i need smith-waterman in php, do you know if there is already an implementation?
I need this algo for proxmity searches ( Function that returns affinity between texts? )
I will try to make it if there aren't any.
thanks
I reverse engineered the SimMetrics java code for SmithWatermanGotoh - I found that SmithWatermanGotoh is more efficient than SmithWaterman with very similar results:
class SmithWatermanGotoh
{
private $gapValue;
private $substitution;
/**
* Constructs a new Smith Waterman metric.
*
* #param gapValue
* a non-positive gap penalty
* #param substitution
* a substitution function
*/
public function __construct($gapValue=-0.5,
$substitution=null)
{
if($gapValue > 0.0) throw new Exception("gapValue must be <= 0");
//if(empty($substitution)) throw new Exception("substitution is required");
if (empty($substitution)) $this->substitution = new SmithWatermanMatchMismatch(1.0, -2.0);
else $this->substitution = $substitution;
$this->gapValue = $gapValue;
}
public function compare($a, $b)
{
if (empty($a) && empty($b)) {
return 1.0;
}
if (empty($a) || empty($b)) {
return 0.0;
}
$maxDistance = min(mb_strlen($a), mb_strlen($b))
* max($this->substitution->max(), $this->gapValue);
return $this->smithWatermanGotoh($a, $b) / $maxDistance;
}
private function smithWatermanGotoh($s, $t)
{
$v0 = [];
$v1 = [];
$t_len = mb_strlen($t);
$max = $v0[0] = max(0, $this->gapValue, $this->substitution->compare($s, 0, $t, 0));
for ($j = 1; $j < $t_len; $j++) {
$v0[$j] = max(0, $v0[$j - 1] + $this->gapValue,
$this->substitution->compare($s, 0, $t, $j));
$max = max($max, $v0[$j]);
}
// Find max
for ($i = 1; $i < mb_strlen($s); $i++) {
$v1[0] = max(0, $v0[0] + $this->gapValue, $this->substitution->compare($s, $i, $t, 0));
$max = max($max, $v1[0]);
for ($j = 1; $j < $t_len; $j++) {
$v1[$j] = max(0, $v0[$j] + $this->gapValue, $v1[$j - 1] + $this->gapValue,
$v0[$j - 1] + $this->substitution->compare($s, $i, $t, $j));
$max = max($max, $v1[$j]);
}
for ($j = 0; $j < $t_len; $j++) {
$v0[$j] = $v1[$j];
}
}
return $max;
}
}
class SmithWatermanMatchMismatch
{
private $matchValue;
private $mismatchValue;
/**
* Constructs a new match-mismatch substitution function. When two
* characters are equal a score of <code>matchValue</code> is assigned. In
* case of a mismatch a score of <code>mismatchValue</code>. The
* <code>matchValue</code> must be strictly greater then
* <code>mismatchValue</code>
*
* #param matchValue
* value when characters are equal
* #param mismatchValue
* value when characters are not equal
*/
public function __construct($matchValue, $mismatchValue) {
if($matchValue <= $mismatchValue) throw new Exception("matchValue must be > matchValue");
$this->matchValue = $matchValue;
$this->mismatchValue = $mismatchValue;
}
public function compare($a, $aIndex, $b, $bIndex) {
return ($a[$aIndex] === $b[$bIndex] ? $this->matchValue
: $this->mismatchValue);
}
public function max() {
return $this->matchValue;
}
public function min() {
return $this->mismatchValue;
}
}
$str1 = "COELACANTH";
$str2 = "PELICAN";
$o = new SmithWatermanGotoh();
echo $o->compare($str1, $str2);
There is this "BioStor" project that has an implementation of the Smith-Waterman algorithm in PHP.
Related
A PHP 7 compatibility check pointed out two errors in some PHP 5 code that is not compatible with PHP 7.
'clone' is a reserved keyword introduced in PHP version 5.0 and
cannot be invoked as a function (T_CLONE)
How can the following code be fixed so it is compatible with PHP 7?
/**
* Implements {#link aCssMinifierFilter::filter()}.
*
* #param array $tokens Array of objects of type aCssToken
* #return integer Count of added, changed or removed tokens; a return value larger than 0 will rebuild the array
*/
public function apply(array &$tokens)
{
$r = 0;
$transformations = array("-moz-keyframes", "-webkit-keyframes");
for ($i = 0, $l = count($tokens); $i < $l; $i++)
{
if (get_class($tokens[$i]) === "CssAtKeyframesStartToken")
{
for ($ii = $i; $ii < $l; $ii++)
{
if (get_class($tokens[$ii]) === "CssAtKeyframesEndToken")
{
break;
}
}
if (get_class($tokens[$ii]) === "CssAtKeyframesEndToken")
{
$add = array();
$source = array();
for ($iii = $i; $iii <= $ii; $iii++)
{
$source[] = clone($tokens[$iii]);
}
foreach ($transformations as $transformation)
{
$t = array();
foreach ($source as $token)
{
$t[] = clone($token);
}
$t[0]->AtRuleName = $transformation;
$add = array_merge($add, $t);
}
if (isset($this->configuration["RemoveSource"]) && $this->configuration["RemoveSource"] === true)
{
array_splice($tokens, $i, $ii - $i + 1, $add);
}
else
{
array_splice($tokens, $ii + 1, 0, $add);
}
$l = count($tokens);
$i = $ii + count($add);
$r += count($add);
}
}
}
return $r;
}
}
So, it looks like the code is trying to clone an object. But, you have parentheses around the method.
The code should read
$t[] = clone $token;
clone isn't a function per se, it's a function that calls an object's __clone method
Hey guys :) I want to ask for some solution. Now, I have dictionary words.txt, here some example:
happy
laugh
sad
And I have the slang string:
hppy
I want to search & match that slang string to my dictionary wich means it will return "happy" because those string refer to "happy" in dictionary.
Recently I've been using similar_text() but doesn't confident about its validity. Can you guys recommend better solution for my problem? Thank you :)
And here i put my codes:
function searchwords($tweet){
//echo $tweet;
$find = false;
$handle = #fopen("words.txt", "r");
if ($handle)
{
while (!feof($handle))
{
$buffer = fgets($handle);
similar_text(trim($tweet),trim($buffer),$percent);
if ($percent == 100){ // this exact match
$find = true;
}else if ($percent >= 90){ //there is the possibility of errors
$find = true;
}
}
fclose($handle);
}
if ($find == true){
unset($tweet);
}else{
return $tweet;
}
}
As answered here
I've found that to calculate a similarity percentage between strings,
the Levenshtein and Jaro Winkler algorithms work well for
spelling mistakes and small changes between strings, while the Smith
Waterman Gotoh algorithm works well for strings where significant
chunks of the text would be the same but with "noise" around the
edges. This answer to a similar question shows more detail on
this.
I included the php examples of using each of these three examples to return a similarity percentage between two strings:
Levenshtein
echo levenshtein("LEGENDARY","BARNEY STINSON");
Jaro Winkler
class StringCompareJaroWinkler
{
public function compare($str1, $str2)
{
return $this->JaroWinkler($str1, $str2, $PREFIXSCALE = 0.1 );
}
private function getCommonCharacters( $string1, $string2, $allowedDistance ){
$str1_len = mb_strlen($string1);
$str2_len = mb_strlen($string2);
$temp_string2 = $string2;
$commonCharacters='';
for( $i=0; $i < $str1_len; $i++){
$noMatch = True;
// compare if char does match inside given allowedDistance
// and if it does add it to commonCharacters
for( $j= max( 0, $i-$allowedDistance ); $noMatch && $j < min( $i + $allowedDistance + 1, $str2_len ); $j++){
if( $temp_string2[$j] == $string1[$i] ){
$noMatch = False;
$commonCharacters .= $string1[$i];
$temp_string2[$j] = '';
}
}
}
return $commonCharacters;
}
private function Jaro( $string1, $string2 ){
$str1_len = mb_strlen( $string1 );
$str2_len = mb_strlen( $string2 );
// theoretical distance
$distance = (int) floor(min( $str1_len, $str2_len ) / 2.0);
// get common characters
$commons1 = $this->getCommonCharacters( $string1, $string2, $distance );
$commons2 = $this->getCommonCharacters( $string2, $string1, $distance );
if( ($commons1_len = mb_strlen( $commons1 )) == 0) return 0;
if( ($commons2_len = mb_strlen( $commons2 )) == 0) return 0;
// calculate transpositions
$transpositions = 0;
$upperBound = min( $commons1_len, $commons2_len );
for( $i = 0; $i < $upperBound; $i++){
if( $commons1[$i] != $commons2[$i] ) $transpositions++;
}
$transpositions /= 2.0;
// return the Jaro distance
return ($commons1_len/($str1_len) + $commons2_len/($str2_len) + ($commons1_len - $transpositions)/($commons1_len)) / 3.0;
}
private function getPrefixLength( $string1, $string2, $MINPREFIXLENGTH = 4 ){
$n = min( array( $MINPREFIXLENGTH, mb_strlen($string1), mb_strlen($string2) ) );
for($i = 0; $i < $n; $i++){
if( $string1[$i] != $string2[$i] ){
// return index of first occurrence of different characters
return $i;
}
}
// first n characters are the same
return $n;
}
private function JaroWinkler($string1, $string2, $PREFIXSCALE = 0.1 ){
$JaroDistance = $this->Jaro( $string1, $string2 );
$prefixLength = $this->getPrefixLength( $string1, $string2 );
return $JaroDistance + $prefixLength * $PREFIXSCALE * (1.0 - $JaroDistance);
}
}
$jw = new StringCompareJaroWinkler();
echo $jw->compare("LEGENDARY","BARNEY STINSON");
Smith Waterman Gotoh
class SmithWatermanGotoh
{
private $gapValue;
private $substitution;
/**
* Constructs a new Smith Waterman metric.
*
* #param gapValue
* a non-positive gap penalty
* #param substitution
* a substitution function
*/
public function __construct($gapValue=-0.5,
$substitution=null)
{
if($gapValue > 0.0) throw new Exception("gapValue must be <= 0");
//if(empty($substitution)) throw new Exception("substitution is required");
if (empty($substitution)) $this->substitution = new SmithWatermanMatchMismatch(1.0, -2.0);
else $this->substitution = $substitution;
$this->gapValue = $gapValue;
}
public function compare($a, $b)
{
if (empty($a) && empty($b)) {
return 1.0;
}
if (empty($a) || empty($b)) {
return 0.0;
}
$maxDistance = min(mb_strlen($a), mb_strlen($b))
* max($this->substitution->max(), $this->gapValue);
return $this->smithWatermanGotoh($a, $b) / $maxDistance;
}
private function smithWatermanGotoh($s, $t)
{
$v0 = [];
$v1 = [];
$t_len = mb_strlen($t);
$max = $v0[0] = max(0, $this->gapValue, $this->substitution->compare($s, 0, $t, 0));
for ($j = 1; $j < $t_len; $j++) {
$v0[$j] = max(0, $v0[$j - 1] + $this->gapValue,
$this->substitution->compare($s, 0, $t, $j));
$max = max($max, $v0[$j]);
}
// Find max
for ($i = 1; $i < mb_strlen($s); $i++) {
$v1[0] = max(0, $v0[0] + $this->gapValue, $this->substitution->compare($s, $i, $t, 0));
$max = max($max, $v1[0]);
for ($j = 1; $j < $t_len; $j++) {
$v1[$j] = max(0, $v0[$j] + $this->gapValue, $v1[$j - 1] + $this->gapValue,
$v0[$j - 1] + $this->substitution->compare($s, $i, $t, $j));
$max = max($max, $v1[$j]);
}
for ($j = 0; $j < $t_len; $j++) {
$v0[$j] = $v1[$j];
}
}
return $max;
}
}
class SmithWatermanMatchMismatch
{
private $matchValue;
private $mismatchValue;
/**
* Constructs a new match-mismatch substitution function. When two
* characters are equal a score of <code>matchValue</code> is assigned. In
* case of a mismatch a score of <code>mismatchValue</code>. The
* <code>matchValue</code> must be strictly greater then
* <code>mismatchValue</code>
*
* #param matchValue
* value when characters are equal
* #param mismatchValue
* value when characters are not equal
*/
public function __construct($matchValue, $mismatchValue) {
if($matchValue <= $mismatchValue) throw new Exception("matchValue must be > matchValue");
$this->matchValue = $matchValue;
$this->mismatchValue = $mismatchValue;
}
public function compare($a, $aIndex, $b, $bIndex) {
return ($a[$aIndex] === $b[$bIndex] ? $this->matchValue
: $this->mismatchValue);
}
public function max() {
return $this->matchValue;
}
public function min() {
return $this->mismatchValue;
}
}
$o = new SmithWatermanGotoh();
echo $o->compare("LEGENDARY","BARNEY STINSON");
Hopefully it'll serve your purpose. But there are some things to keep in mind while working with similar_text().
matching percentage can differ depending on the order of parameters. ie: similar_text($a, $b, $percent) and similar_text($b, $a, $percent) here in both cases $percent may not be same.
Note that this function is case sensitive: so while passing $a and $b pass both either in uppercase or lowercase.
for more info check this page
What's an elegant code for finding common alphabets among two strings without including the space in PHP?
Also return a similarity index i.e. count the number of common characters and return that as a percentage over the total number of characters.
Suppose i have one string "LEGENDARY ", whereas other as "BARNEY STINSON" so i need to find common letters b/w both without including space.
Also my code should return a similarity index i.e. count the number of common characters and return that as a percentage over the total number of characters.
For these two strings, the common characters are "ARNEY" so the score is 5/22 ~= 22%. Any help on this?
I've found that to calculate a similarity percentage between strings, the Levenshtein and Jaro Winkler algorithms work well for spelling mistakes and small changes between strings, while the Smith Waterman Gotoh algorithm works well for strings where significant chunks of the text would be the same but with "noise" around the edges. This answer to a similar question shows more detail on this.
Here are php examples of using each of these three examples to return a similarity percentage between two strings:
Levenshtein
echo levenshtein("LEGENDARY","BARNEY STINSON");
Jaro Winkler
class StringCompareJaroWinkler
{
public function compare($str1, $str2)
{
return $this->JaroWinkler($str1, $str2, $PREFIXSCALE = 0.1 );
}
private function getCommonCharacters( $string1, $string2, $allowedDistance ){
$str1_len = mb_strlen($string1);
$str2_len = mb_strlen($string2);
$temp_string2 = $string2;
$commonCharacters='';
for( $i=0; $i < $str1_len; $i++){
$noMatch = True;
// compare if char does match inside given allowedDistance
// and if it does add it to commonCharacters
for( $j= max( 0, $i-$allowedDistance ); $noMatch && $j < min( $i + $allowedDistance + 1, $str2_len ); $j++){
if( $temp_string2[$j] == $string1[$i] ){
$noMatch = False;
$commonCharacters .= $string1[$i];
$temp_string2[$j] = '';
}
}
}
return $commonCharacters;
}
private function Jaro( $string1, $string2 ){
$str1_len = mb_strlen( $string1 );
$str2_len = mb_strlen( $string2 );
// theoretical distance
$distance = (int) floor(min( $str1_len, $str2_len ) / 2.0);
// get common characters
$commons1 = $this->getCommonCharacters( $string1, $string2, $distance );
$commons2 = $this->getCommonCharacters( $string2, $string1, $distance );
if( ($commons1_len = mb_strlen( $commons1 )) == 0) return 0;
if( ($commons2_len = mb_strlen( $commons2 )) == 0) return 0;
// calculate transpositions
$transpositions = 0;
$upperBound = min( $commons1_len, $commons2_len );
for( $i = 0; $i < $upperBound; $i++){
if( $commons1[$i] != $commons2[$i] ) $transpositions++;
}
$transpositions /= 2.0;
// return the Jaro distance
return ($commons1_len/($str1_len) + $commons2_len/($str2_len) + ($commons1_len - $transpositions)/($commons1_len)) / 3.0;
}
private function getPrefixLength( $string1, $string2, $MINPREFIXLENGTH = 4 ){
$n = min( array( $MINPREFIXLENGTH, mb_strlen($string1), mb_strlen($string2) ) );
for($i = 0; $i < $n; $i++){
if( $string1[$i] != $string2[$i] ){
// return index of first occurrence of different characters
return $i;
}
}
// first n characters are the same
return $n;
}
private function JaroWinkler($string1, $string2, $PREFIXSCALE = 0.1 ){
$JaroDistance = $this->Jaro( $string1, $string2 );
$prefixLength = $this->getPrefixLength( $string1, $string2 );
return $JaroDistance + $prefixLength * $PREFIXSCALE * (1.0 - $JaroDistance);
}
}
$jw = new StringCompareJaroWinkler();
echo $jw->compare("LEGENDARY","BARNEY STINSON");
Smith Waterman Gotoh
class SmithWatermanGotoh
{
private $gapValue;
private $substitution;
/**
* Constructs a new Smith Waterman metric.
*
* #param gapValue
* a non-positive gap penalty
* #param substitution
* a substitution function
*/
public function __construct($gapValue=-0.5,
$substitution=null)
{
if($gapValue > 0.0) throw new Exception("gapValue must be <= 0");
//if(empty($substitution)) throw new Exception("substitution is required");
if (empty($substitution)) $this->substitution = new SmithWatermanMatchMismatch(1.0, -2.0);
else $this->substitution = $substitution;
$this->gapValue = $gapValue;
}
public function compare($a, $b)
{
if (empty($a) && empty($b)) {
return 1.0;
}
if (empty($a) || empty($b)) {
return 0.0;
}
$maxDistance = min(mb_strlen($a), mb_strlen($b))
* max($this->substitution->max(), $this->gapValue);
return $this->smithWatermanGotoh($a, $b) / $maxDistance;
}
private function smithWatermanGotoh($s, $t)
{
$v0 = [];
$v1 = [];
$t_len = mb_strlen($t);
$max = $v0[0] = max(0, $this->gapValue, $this->substitution->compare($s, 0, $t, 0));
for ($j = 1; $j < $t_len; $j++) {
$v0[$j] = max(0, $v0[$j - 1] + $this->gapValue,
$this->substitution->compare($s, 0, $t, $j));
$max = max($max, $v0[$j]);
}
// Find max
for ($i = 1; $i < mb_strlen($s); $i++) {
$v1[0] = max(0, $v0[0] + $this->gapValue, $this->substitution->compare($s, $i, $t, 0));
$max = max($max, $v1[0]);
for ($j = 1; $j < $t_len; $j++) {
$v1[$j] = max(0, $v0[$j] + $this->gapValue, $v1[$j - 1] + $this->gapValue,
$v0[$j - 1] + $this->substitution->compare($s, $i, $t, $j));
$max = max($max, $v1[$j]);
}
for ($j = 0; $j < $t_len; $j++) {
$v0[$j] = $v1[$j];
}
}
return $max;
}
}
class SmithWatermanMatchMismatch
{
private $matchValue;
private $mismatchValue;
/**
* Constructs a new match-mismatch substitution function. When two
* characters are equal a score of <code>matchValue</code> is assigned. In
* case of a mismatch a score of <code>mismatchValue</code>. The
* <code>matchValue</code> must be strictly greater then
* <code>mismatchValue</code>
*
* #param matchValue
* value when characters are equal
* #param mismatchValue
* value when characters are not equal
*/
public function __construct($matchValue, $mismatchValue) {
if($matchValue <= $mismatchValue) throw new Exception("matchValue must be > matchValue");
$this->matchValue = $matchValue;
$this->mismatchValue = $mismatchValue;
}
public function compare($a, $aIndex, $b, $bIndex) {
return ($a[$aIndex] === $b[$bIndex] ? $this->matchValue
: $this->mismatchValue);
}
public function max() {
return $this->matchValue;
}
public function min() {
return $this->mismatchValue;
}
}
$o = new SmithWatermanGotoh();
echo $o->compare("LEGENDARY","BARNEY STINSON");
see similar_text(). And if you want to exclude spaces simple str_replace(' ', '', $string); prior.
echo similar_text ( 'LEGENDARY' , 'BARNEYSTINSON', $percent); // outputs 3
echo $percent; // outputs 27.272727272727
Here's another way using only unique characters
<?php
function unique_chars($string) {
return count_chars(strtolower(str_replace(' ', '', $string)), 3);
}
function compare_strings($a, $b) {
$index = similar_text(unique_chars($a), unique_chars($b), $percent);
return array('index' => $index, 'percent' => $percent);
}
print_r( compare_strings('LEGENDARY', 'BARNEY STINSON') );
// outputs:
?>
Array
(
[index] => 5
[percent] => 55.555555555556
)
how do I compute the z-score of a array of numbers using PHP? I need to compute the z-score and then find the percentile (CDF)! what PHP functions can I use? thanks!
The following code will give a good approximation of the CDF (Abramowitz & Stegun (1964))
function normal_pdf($x) {
return exp(-$x * $x / 4) / sqrt(2 * M_PI);
}
function normal_cdf($x) {
$b = array(0.2316419, 0.319381530, -0.356563782, 1.781477937, -1.821255978, 1.330274429);
$t = 1 / (1 + $b[0] * $x);
$result = 0;
for ($i = 1; $i < 6; $i++) {
$result += $b[$i] * pow($t, $i);
}
return 1 - normal_pdf($x) * $result;
}
This assumes a standard normal distribution. Recall that to standardize, use z = (x - mean) / (standard deviation)
/* Mean */
function mean($input_array)
{
$total = 0;
foreach ($input_array as $value)
{
$total += $value;
}
return ($total / count($input_array));
}
/* Standard Deviation */
function std($arr)
{
if (!count($arr))
return 0;
$mean = mean($arr);
$sos = 0; // Sum of squares
for ($i = 0; $i < count($arr); $i++)
{
$sos += ($arr[$i] - $mean) * ($arr[$i] - $mean);
}
return sqrt($sos / (count($arr) - 1));
}
/* Z Scores */
function z($var, $arr)
{
return ($var -mean($arr)) / std($arr);
}
There are a few functions in the PHP statistics extension that could help you — You probably want stats_standard_deviation for a start.
$control=array(15,7);
$treatment=array(46,8);
$confidence=number_format(cumnormdist(zscore($control, $treatment))*100,0);
function cr($t)
{
return $t[1]/$t[0];
}
function zscore($c, $t)
{
$z = cr($t)-cr($c);
$s = (cr($t)*(1-cr($t)))/$t[0] + (cr($c)*(1-cr($c)))/$c[0];
return $z/sqrt($s);
}
function cumnormdist($x)
{
$b1 = 0.319381530;
$b2 = -0.356563782;
$b3 = 1.781477937;
$b4 = -1.821255978;
$b5 = 1.330274429;
$p = 0.2316419;
$c = 0.39894228;
if($x >= 0.0) {
$t = 1.0 / ( 1.0 + $p * $x );
return (1.0 - $c * exp( -$x * $x / 2.0 ) * $t *
( $t *( $t * ( $t * ( $t * $b5 + $b4 ) + $b3 ) + $b2 ) + $b1 ));
}
else {
$t = 1.0 / ( 1.0 - $p * $x );
return ( $c * exp( -$x * $x / 2.0 ) * $t *
( $t *( $t * ( $t * ( $t * $b5 + $b4 ) + $b3 ) + $b2 ) + $b1 ));
}
}
i'v been trying to implement merge sort under php. but seems unsuccessful :( couldn't find source of error. any kind of help is very much appreciated!
function merge_sort(&$input, $start, $end) {
if($start < $end) {
$mid = (int) floor($start + $end / 2);
merge_sort($input, $start, $mid);
merge_sort($input, $mid + 1, $end);
merge($input, $start, $mid, $end);
}
}
function merge(&$input, $p, $q, $r) {
$a = $q - $p + 1;
$b = $r - $q;
for($i = $p;$i <= $q;$i++) {
$arr1[] = $input[$i];
}
for($i = $q+1;$i <= $r;$i++) {
$arr2[] = $input[$i];
}
$c = $d = 0;
for($i = $p; $i <= $r; $i++) {
$s = $arr1[$c];
$t = $arr2[$d];
if($a && (($s <= $t) || !$b)) {
$input[$i] = $s;
$a--;$c++;
} else if($b) {
$input[$i] = $t;
$b--;$d++;
}
}
return true;
}
here's the info xdebug throw back:
Fatal error: Maximum function nesting level of '100' reached, aborting!
To reach a nesting level of 100 on a merge sort, you would need to have an input array of size 2^100(about 1e30), which is impossible. I suspect your recursion is incorrect. For instance, you wrote $start + $end / 2 instead of ($start + $end) / 2.
Set
xdebug.max_nesting_level=500
in my php.ini
Here's my working solution, feel free to compare...
/**
* #param array $items array to sort
* #param int $l left index (defaults to 0)
* #param int $r right index (defaults to count($items)-1)
*/
function mergeSort(&$items, $l = 0, $r = null)
{
if (!isset($r)) {
$r = count($items) - 1;
}
if ($l < $r) {
$m = floor(($r - $l) / 2) + $l;
mergeSort($items, $l, $m);
mergeSort($items, $m + 1, $r);
merge($items, $l, $m, $r);
}
}
/**
* #param array $items array to merge
* #param int $l left index
* #param int $m middle index
* #param int $r right index
*/
function merge(&$items, $l, $m, $r)
{
$itemsA = array_slice($items, $l, $m + 1 - $l);
$itemsB = array_slice($items, $m + 1, ($r + 1) - ($m + 1));
$a = 0;
$aCount = count($itemsA);
$b = 0;
$bCount = count($itemsB);
for ($i = $l; $i <= $r; $i++) {
if ($a < $aCount && ($b == $bCount || $itemsA[$a] <= $itemsB[$b])) {
$items[$i] = $itemsA[$a++];
} else {
$items[$i] = $itemsB[$b++];
}
}
}
$items = array(5,3,6,1,2,3,9,10,7,2,4,8);
mergeSort($items);
echo implode(',', $items) . "\n";
Outputs:
1,2,2,3,3,4,5,6,7,8,9,10
There is a maximum function nesting level of '100', and you have reached it. Your recursive function goes too deep.
From http://www.xdebug.org/docs/all_settings:
xdebug.max_nesting_level
Type: integer, Default value: 100
Controls the protection mechanism for infinite recursion protection. The value of this setting is the maximum level of nested functions that are allowed before the script will be aborted.
You are going too deep in your recursive function triggering this xdebug error. Try raising this limit and see if that helps.
Also, here is an interesting article about recursion and PHP: http://www.alternateinterior.com/2006/09/tail-recursion-in-php.html
PHP is not a good language for recursive algorithms. From the manual:
It is possible to call recursive
functions in PHP. However avoid
recursive function/method calls with
over 100-200 recursion levels as it
can smash the stack and cause a
termination of the current script.
If you need to do it in PHP, you'll probably have to find an iterative version of the algorithm. You've hit a hard-coded limit in the language.
Cosi dovrebbe funzionare!!!! www.dslpg.it
function merge ( &$a, $left, $center, $right ) { //left = p right = r center = q
$n1 = $center - $left + 1;
$n2 = $right - $center;
for ($i = 1; $i <= $n1; $i++) $L[$i] = $a[$left+$i-1];
for ($i = 1; $i <= $n2; $i++) $R[$i] = $a[$center+$i];
$L[$n1+1] = 99999;
$R[$n2+1] = 99999;
$i = 1;
$j = 1;
for ($k = $left; $k <= $right; $k++) {
if ($L[$i] <= $R[$j] ) {
$a[$k] = $L[$i];
echo $a[$k];
$i++;
}
else {
$a[$k] = $R[$j];
echo $a[$k];
$j++;
}
}
return $a;
}
function merge_sort ( &$a, $left, $right ) { //left = p right = r
if ( $left < $right ) {
$center = (int) floor(($left + $right) / 2 );
merge_sort ($a, $left, $center);
merge_sort ($a, $center+1, $right);
merge ($a, $left, $center, $right);
}
}
merge_sort ( $a, 1, $n );