I have this simple quicksort function (I got it from uncle "G")
function quicksort( &$list, $l , $r ) {
$i = $l;
$j = $r;
$tmp = $list[(int)( ($l+$r)/2 )];
do {
while( $list[$i] < $tmp )
$i++;
while( $tmp < $list[$j] )
$j--;
if( $i <= $j ) {
$w = $list[$i];
$list[$i] = $list[$j];
$list[$j] = $w;
//_swp($list[$i],$list[$j]);
$i++;
$j--;
}
}while( $i <= $j );
if( $l < $j )
quicksort($list, $l, $j);
if( $i < $r )
quicksort($list, $i, $r);
return $list;
}
And I have this little function to swap two variables.
function _swp(&$a,&$b){
$a=$a+$b;
$b=$a-$b;
$a=$a-$b;
}
How come I can't use _swp($a,$b) in quicksort function instead of this lines?
$w = $list[$i];
$list[$i] = $list[$j];
$list[$j] = $w;
If I comment out these 3 lines of code and enter call to _swp function I got bad results...
Please explain.
Best regards
the unexpected behavior is probably the "random" occurence of zeros in the sorted list. This happens because there is a special case while swapping:
if( $i <= $j ) {
// swapping here using references!
_swp($list[$i],$list[$j]);
$i++;
$j--;
}
The problem is found directly in the condition for swapping itself: if $i==$j then there are two references to the same variable. Thus calling _swp($list[$i],$list[$j]); will firstly add both variables $a = $a + $b. Considering $a and $b actually access the same variable content, $a and $b will then have the same value. In the next step $b = $a - $b will then be zero as $a is equal to $b. The third operation will leave the result to 0.
An easy solution for this is inserting another condition:
if( $i <= $j ) {
// ensure $i to be truly smaller than $j
if( $i < $j ) {
_swp($list[$i],$list[$j]);
}
$i++;
$j--;
}
I hope this will help you.
Cheers,
Fabian
Related
I am coding LCS(longest common subsequence) in php program by using recursive approach. I have the following code:
<?php
$lcsTbl = array(array(128),array(128));
$backTracks = array(array(128),array(128));
$str1 = 'asdvadsdad';
$str2 = 'asdasdadasda';
$len1 = strlen($str1);
$len2 = strlen($str2);
echo LCS_Length($lcsTbl, $backTracks, $str1, $str2, $len1, $len2); //longest common sub sequence
echo '<br/>';
function LCS_Length(&$LCS_Length_Table, &$B, &$s1, &$s2, &$m, &$n)
{
//reset the 2 cols in the table
for($i=1; $i < $m; $i++) $LCS_Length_Table[$i][0]=0;
for($j=0; $j < $n; $j++) $LCS_Length_Table[0][$j]=0;
for ($i=1; $i <= $m; $i++) {
for ($j=1; $j <= $n; $j++) {
if ($s1[$i-1]==$s2[$j-1])
{ $LCS_Length_Table[$i][$j] = $LCS_Length_Table[$i-1][$j-1] + 1; $B[$i][$j] = '\\';}
else if ($LCS_Length_Table[$i-1][$j] >= $LCS_Length_Table[$i][$j-1])
{ $LCS_Length_Table[$i][$j] = $LCS_Length_Table[$i-1][$j]; $B[$i][$j] = '|';}
else
{ $LCS_Length_Table[$i][$j] = $LCS_Length_Table[$i][$j-1]; $B[$i][$j] = '-';}
}
}
return $LCS_Length_Table[$m][$n];
}
To print the LCS, I call the following function:
$x = str_split($str1);
echo lcs_print($backTracks, $str1, $len1, $len2); //print longest common sub sequence
function lcs_print(&$B, &$x, &$i, &$j)
{
if( $i == 0 || $j == 0 )
return;
if( $B[$i][$j] == '\\' ) {
echo $x[$i-1];
lcs_print( $B, $x, $i = $i-1, $j = $j-1 );
} else if( $B[$i][$j] == '|' ) {
lcs_print( $B, $x, $i = $i-1, $j );
} else {
lcs_print( $B, $x, $i, $j = $j-1 );
}
}
?>
This code counts the total lengthof LCS correctly but gives "Notice: Undefined offset: -1" on every call of this line in print function echo $x[$i-1]; and prints nothing. I have tried almost everything to split the string of $str1 and then pass it to function, but nothing works. It does not print LCS string because something is wrong with this line of code echo $x[$i-1]; which I am unable to get. Please help.
Note: The pseudocode of the above code has been taken from book of Thomas H. Cormen, "Introduction to Algorithms 3rd Edition". I am writing it into PHP with the intention of extending it so that it can print LCS of more than two strings. I'll appreciate if anyone shares idea of How can I extend this code so that it can print LCS of an array with multiple strings like $array{'sdsad','asddaw','asd',...n}. Later, I intend to convert the entire program into MATLAB.
There are issues in your LCS_length
1.if ($s1[$i-1]==$s2[$j-1]) ,it should have been if ($s1[$i]==$s2[$j])
2.your boundary condition ($j=0; $j < $n) is unclear, you need to include this upperbound
and you are trying to print it calling this lcs_print($backTracks, $str1, $len1, $len2).
It should have been ($j=0;$j<=n;$j++)
I think these changes will solve the problem.
I haven't done coding in PHP so can't say about the syntaxes.
I have solved the error: I have placed echo $x[$i-1]; before lcs_print( $B, $x, $i = $i-1, $j = $j-1 ); in lcs_print function, all is working fine now.
I want to tell my array to start from key position 2 and then loop through the entire array, including the values before key position 2. I just want to use one array and specify the key position I start looping from. For example, here I am using array_splice, but it does not do what I want it to, could you help me please?
$names = array('Bill', 'Ben', 'Bert', 'Ernie');
foreach(array_slice($names, 2) as $name){
echo $name;
}
foreach(array_slice($names, 3) as $name){
echo $name;
}
If the keys are irrelevant, you can splice the array twice, and merge the resulting arrays, like this:
$names = array('Bill', 'Ben', 'Bert', 'Ernie');
$start = 2;
foreach( array_merge( array_slice($names, $start), array_slice( $names, 0, $start)) as $name){
echo $name;
}
You can see from the demo that this prints:
BertErnieBillBen
Alternatively, for efficiency, you can use two loops that are aware of wrapping around to the beginning, which will be more efficient since you are operating on the original array and not creating copies of it.
$start = 2;
for( $i = $start, $count = count( $names); $i < $count; $i++) {
echo $names[$i];
}
$i = 0;
while( $i < $start) {
echo $names[$i++];
}
You could also turn this into one single loop, and just encapsulate the logic for wrapping around inside the for.
$limit = 2; //so you can set your start index to an arbitrary number
$fn= function($a,$b) use ($limit){
if(($a < $limit && $b < $limit)
|| ($a >= $limit && $b >=$limit)) //$a and $b on the same side of $limit
return $a < $b ? -1 : ($a==$b ? 0 : 1);
if($a < $limit && $b > $limit) return 1; //because $a will always be considered greater
if($a >= $limit && $b < $limit) return -1; //because $b will always be considered greater
};
uksort($arr, $fn);
foreach($arr as $v) echo $v;
The code below will create an array for all possible combination that can occur when you have four different variables. The variables always need to equal 1. The for loops I have created work and I understand how to make this work for more variables, but can I make this dynamic? I need to have a function that has how many variables there are as a parameter. If there are three variables create the three forloops. If there are 10... create the 10 corresponding for loops to determine all possible combinations.
$anarray2 = array();
for( $a = 1; $a <= 97; $a++ ) {
for( $b = 1; $a + $b <=98 ; $b++ ) {
for( $c = 1; $a + $b + $c <= 99; $c++ ) {
$d = 100 - ( $a + $b + $c );
$var_1 = $a / 100;
$var_2 = $b / 100;
$var_3 = $c / 100;
$var_4 = $d / 100;
$anarray2[] = array( $var_1, $var_2, $var_3, $var_4 );
}
}
}
print_array( $anarray2 );
You're effectively looking to share out I identical items to N people in all of the different possible ways.
If there is one person (N==1), then there is only one way to do this - give that person all I items.
If there is more than one person (N>1), then we can consider how many items can be assigned to the first person, and then what the possible assignments are for the remaining N-1 people in each case.
This leads to a nice recursive solution. Firstly we solve the problem for N=1:
function assign($I, $N) {
$anarray = array();
if ($N == 1) {
$anarray[] = array($I);
} else {
// Coming up...
}
return $anarray;
}
Now we solve the problem for N=k (some constant) in terms of N=k-1 - that is, we solve the problem using the solution to a smaller problem. This will reach all the way back to the solution when N=1.
function assign($I, $N) {
$anarray = array();
if ($N == 1) {
$anarray[] = array($I);
} else {
for ($i = $I; $i < $I; $i++) {
foreach (assign($I - $i, $N - 1) as $subproblem) {
$anarray[] = array_merge(array($i), $subproblem);
}
}
}
return $anarray;
}
Something like that should do the job.
This question already has answers here:
How can I sort arrays and data in PHP?
(14 answers)
Closed 7 years ago.
I need to do a bubble sort algorithm in PHP.
I want to know whether any one has any good examples that I can use, or an open source library which can do this.
I have a few spaces in a set (array), i want to fill these spaces with object (a person), so no space can have a male and a female, this why i am trying to find out a bubble sort algorithm.
My plan is to fill in any of the available spaces regardless of the gender, and after that sort them separately.
Thanks.
function bubble_sort($arr) {
$size = count($arr)-1;
for ($i=0; $i<$size; $i++) {
for ($j=0; $j<$size-$i; $j++) {
$k = $j+1;
if ($arr[$k] < $arr[$j]) {
// Swap elements at indices: $j, $k
list($arr[$j], $arr[$k]) = array($arr[$k], $arr[$j]);
}
}
}
return $arr;
}
For example:
$arr = array(1,3,2,8,5,7,4,0);
print("Before sorting");
print_r($arr);
$arr = bubble_sort($arr);
print("After sorting by using bubble sort");
print_r($arr);
Using bubble sort is a very bad idea. It has complexity of O(n^2).
You should use php usort, which is actually a merge sort implementation and guaranteed O(n*log(n)) complexity.
A sample code from the PHP Manual -
function cmp( $a, $b ) {
if( $a->weight == $b->weight ){ return 0 ; }
return ($a->weight < $b->weight) ? -1 : 1;
}
usort($unsortedObjectArray,'cmp');
$numbers = array(1,3,2,5,2);
$array_size = count($numbers);
echo "Numbers before sort: ";
for ( $i = 0; $i < $array_size; $i++ )
echo $numbers[$i];
echo "n";
for ( $i = 0; $i < $array_size; $i++ )
{
for ($j = 0; $j < $array_size; $j++ )
{
if ($numbers[$i] < $numbers[$j])
{
$temp = $numbers[$i];
$numbers[$i] = $numbers[$j];
$numbers[$j] = $temp;
}
}
}
echo "Numbers after sort: ";
for( $i = 0; $i < $array_size; $i++ )
echo $numbers[$i];
echo "n";
function bubble_sort($arr) {
$n = count($arr);
do {
$swapped = false;
for ($i = 0; $i < $n - 1; $i++) {
// swap when out of order
if ($arr[$i] > $arr[$i + 1]) {
$temp = $arr[$i];
$arr[$i] = $arr[$i + 1];
$arr[$i + 1] = $temp;
$swapped = true;
}
}
$n--;
}
while ($swapped);
return $arr;
}
function bubbleSort(array $arr)
{
$n = sizeof($arr);
for ($i = 1; $i < $n; $i++) {
for ($j = $n - 1; $j >= $i; $j--) {
if($arr[$j-1] > $arr[$j]) {
$tmp = $arr[$j - 1];
$arr[$j - 1] = $arr[$j];
$arr[$j] = $tmp;
}
}
}
return $arr;
}
// Example:
$arr = array(255,1,22,3,45,5);
$result = bubbleSort($arr);
print_r($result);
//====================================================
//------- improved version----------------------------
//====================================================
function bubbleSortImproved(array $arr)
{
$n = sizeof($arr);
for ($i = 1; $i < $n; $i++) {
$flag = false;
for ($j = $n - 1; $j >= $i; $j--) {
if($arr[$j-1] > $arr[$j]) {
$tmp = $arr[$j - 1];
$arr[$j - 1] = $arr[$j];
$arr[$j] = $tmp;
$flag = true;
}
}
if (!$flag) {
break;
}
}
return $arr;
}
// Example:
$arr = array(255,1,22,3,45,5);
$result = bubbleSortImproved($arr);
print_r($result);
Improved Bubble Sorting enjoy :)
$sortarr = array(3,5,15,3,2,6,7,50,1,4,5,2,100,9,3,2,6,7,13,18);
echo "<pre>";
// Array to be sorted
print_r($sortarr);
// Sorted Array
print_r(bubble_sort($sortarr));
echo "<pre>";
function bubble_sort($sortarr){
// Bubble sorting
$array_count = count($sortarr);
for($x = 0; $x < $array_count; $x++){
for($a = 0 ; $a < $array_count - 1 ; $a++){
if($a < $array_count ){
if($sortarr[$a] > $sortarr[$a + 1] ){
swap($sortarr, $a, $a+1);
}
}
}
}
return $sortarr;
}
function swap(&$arr, $a, $b) {
$tmp = $arr[$a];
$arr[$a] = $arr[$b];
$arr[$b] = $tmp;
}
Maybe someone finds useful my version of Bubble Sort:
function BubbleSort(&$L)
{
$rm_key = count($L);
while( --$rm_key > -1 )#after this the very first time it will point to the last element
for($i=0; $i<$rm_key; $i++)
if( $L[$i] > $L[$i+1] )
list($L[$i],$L[$i+1]) = array($L[$i+1],$L[$i]);
}
I got the swap idea (using list) from above comment.
<?php
$i == array(1, 2);
$j == array(a, b);
$m == count($j);
$n == count($i);
for ( $i = 0; $i < $m; i++ )
{
for ( $j = 0; j < $n; j++)
{ echo $i."x"$j; }
}
?>
The error is referencing line 6: for ( $i = 0; $i < $m; i++ )
for ( $i = 0; $i < $m; $i++ )
Note the dollar sign I added before the i++
Same goes for your other for statement:
for ( $j = 0; $j < $n; $j++ )
Wierd error indeed, but it i is not a variable (although PHP might flag a E_NOTICE and convert it to 'i'. You want to reference your variable, so you must add a $ before.
Most likely what you want is:
<?php
$iArray = array(1, 2);
$jArray = array('a', 'b');
$n = count($iArray);
$m = count($jArray);
for ( $i = 0; $i < $n; $i++) {
for ( $j = 0; $j < $m; $j++) {
echo $iArray[$i] . "x" . $jArray[$j];
}
}
?>
The things I changed:
== is used for comparison, = is used for assignment
The second array I assumed you wanted the string literals 'a' and 'b', but you could have also wanted $a and $b if you declared those variables somewhere else
you assign $i to an array, but then in your for loop you overwrite it with $i = 0. You most likely want two variables
missing $s, like I mentioned above
$m was being used for the number of variables in $jArray, but you used it to iterate over $iArray
So just a few pointers, brush up on you PHP and try to make sure your code works with every little change. Make 1 modification, then run it. It is very easy to get lost in syntax for PHP since it is such a dynamic scripting language
You have a bunch of equality checks there. I'm assuming you were actually assigning variables rather than checking for equality.
Change all == equality checks to assignments (=)
You also have improper concatenation on line 9 and I added a comment pointing out another possible error.
$i == array(1, 2);
$j == array($a, $b); // <--Put in $ signs if these are variables in the array
$m == count($j);
$n == count($i);
for ( $i = 0; $i < $m; $i++ )
{
for ( $j = 0; $j < $n; $j++)
{ echo $i."x".$j; }
}