code
function test($arr, $str = ''){
$len = count($arr);
if($len == 1){
echo $str . $arr[0] . PHP_EOL;
return;
}
for ($i = 0; $i < count($arr); $i++) {
$tmp = $arr[0];
$arr[0] = $arr[$i];
$arr[$i] = $tmp;
test(array_slice($arr, 1), $str . $arr[0]);
}
}
$string = 'abcdef';
test(str_split($string));
原理分析
首先不考虑递归,只说函数本身的这个for循环,它的作用是让每个元素都和第一个元素交换一次位置。
然后把数组第一个元素拿掉,进行递归,这样后面的元素也都是这个逻辑,让每个元素和第一个元素交换一次位置。
然后分析递归,简单点,假设字符串是abcd
那么随着递归的进行,参数传入分别是:
([a,b,c,d],’’) (首次调用函数)
([b,c,d],a) (第一层递归)
([c,d],ab) (第二层递归)
([d],abc) (第三层递归)
当数组元素为1个时,根据逻辑将会输出 abcd , 然后return,此时回到第二层递归的for循环中。
for循环再次执行后再次交换元素,此时$i
的值为1,$arr[0]
和$arr[$i]
进行元素交换后,$arr[0]
的值为d,$arr[$i]
的值为c。
然后再次进入第三层递归,此时的传参是: ([c],abd),然后第三层的递归根据逻辑会输出 abdc ,然后再return到第二层递归中。
当第二层递归循环完之后,第一次递归的for循环会继续执行,然后以此类推…
由此可见,每一层递归当中,都是负责将自己收到的数组的每个元素和第一个元素进行一次交换,然后传递下去,每一层递归都可以保证从自己这一层开始,后面的元素都能得到充分的交换,这也就达到了打印一个字符串所有排列方式的目的。
这种实现的缺点是,计算时所损耗的内存会随着字符串长度增加而增加。