Quicksort is a comparison sort and, in efficient implementations, is not a stable sort.
PHP implementation:
// Recursive version:
function quickSortRecursive( $arr, $left = 0 , $right = NULL )
{
// when the call is recursive we need to change
//the array passed to the function yearlier
static $array = array();
if( $right == NULL )
$array = $arr;
if( $right == NULL )
$right = count($array)-1;//last element of the array
$i = $left;
$j = $right;
$tmp = $array[(int)( ($left+$right)/2 )];
// partion the array in two parts.
// left from $tmp are with smaller values,
// right from $tmp are with bigger ones
do
{
while( $array[$i] < $tmp )
$i++;
while( $tmp < $array[$j] )
$j--;
// swap elements from the two sides
if( $i <= $j )
{
$w = $array[$i];
$array[$i] = $array[$j];
$array[$j] = $w;
$i++;
$j--;
}
}while( $i <= $j );
// devide left side if it is longer the 1 element
if( $left < $j )
quickSortRecursive(NULL, $left, $j);
// the same with the right side
if( $i < $right )
quickSortRecursive(NULL, $i, $right);
// when all partitions have one element
// the array is sorted
return $array;
}
// Non recursive version:
function quickSort( $array )
{
$cur = 1;
$stack[1]['l'] = 0;
$stack[1]['r'] = count($array)-1;
do
{
$l = $stack[$cur]['l'];
$r = $stack[$cur]['r'];
$cur--;
do
{
$i = $l;
$j = $r;
$tmp = $array[(int)( ($l+$r)/2 )];
// partion the array in two parts.
// left from $tmp are with smaller values,
// right from $tmp are with bigger ones
do
{
while( $array[$i] < $tmp )
$i++;
while( $tmp < $array[$j] )
$j--;
// swap elements from the two sides
if( $i <= $j )
{
$w = $array[$i];
$array[$i] = $array[$j];
$array[$j] = $w;
$i++;
$j--;
}
}while( $i <= $j );
if( $i < $r )
{
$cur++;
$stack[$cur]['l'] = $i;
$stack[$cur]['r'] = $r;
}
$r = $j;
}while( $l < $r );
}while( $cur != 0 );
return $array;
}
6 comments:
thanx
Hi there... Thanks for sharing those functions. In testing your implementation of the Recursive function, I found that it fails to sort correctly on larger arrays containing multiple repetitive numbers, i.e. array(4,3,5,2,9,7,1,6,8,3,9,1,4,3,5,2,9,7,1,6,8,3,9,1,4,3,5,2,9,7,1,6,8,3,9,1,4,3,5,2,9,7,1,6,8,3,9,1,4,3,5,2,9,7,1,6,8,3,9,1,4,3,5,2,9,7,1,6,8,3,9,1,4,3,5,2,9,7,1,6,8,3,9,1);
When running the recursive function against this array I get several numbers that land in the wrong position. I am working on figuring out why. Thought I would point it out for the time being.
Oops - my array got chopped, so I am reposting it with carriage returns.
array(4,3,5,2,9,7,1,6,8,3,9,1,4,3,5,2,9,7,1,6,8,3,9,1,4,
3,5,2,9,7,1,6,8,3,9,1,4,3,5,2,9,7,1,6,8,3,9,1,4,3,5,2,9,
7,1,6,8,3,9,1,4,3,5,2,9,7,1,6,8,3,9,1,4,3,5,2,9,7,1,
6,8,3,9,1);
I had no problem, the non recursive seems to work flawlessly. Did you ever find your problem?? If so can you post the solution or even an example of the fail. I was using arrays with a random length between 10 and 100, and values between 0 and PHP_INT_MAX.
I created an associate non-recursive version which is almost as fast as the original and still faster than the recursive version. I have shared it below. Thanks for the inspiration.
function QuickSortAssociateNonRecursive($array) {
$keys = array_keys( $array );
$values = array_values( $array );
$stackleft[$cur = 1] = 0;
$stackright[$cur] = count($array) - 1;
do {
$l = $stackleft[$cur];
$r = $stackright[$cur--];
do {
$tmp = $values[(int) ( (($i = $l) + ($j = $r)) / 2 )];
do {
while ($values[$i] < $tmp)
$i++;
while ($tmp < $values[$j])
$j--;
if ($i <= $j) {
$ki = $keys[$i];
// $kj = $keys[$j];
$values[$i] = $array[$keys[$i] = $keys[$j]];
$values[$j] = $array[$keys[$j] = $ki];
// $w = $values[$i];
// $values[$i] = $values[$j];
// $values[$j] = $w;
// $keys[$i] = $kj;
// $keys[$j] = $ki;
$i++;
$j--;
}
} while ($i <= $j);
if ($i < $r) {
$stackleft[++$cur] = $i;
$stackright[$cur] = $r;
}
} while ($l < ($r = $j));
} while ($cur);
return array_combine($keys, $values);
}
Hi
What happens when executing 'quickSortRecursive($arr,,3), and php tries to assign $tmp using $array, does $array have elements?
Thanks in advance, Manuel Lorenzo
Post a Comment