如下:
在编程的过程中,我们常常要碰到这样一个问题:有n个数,要从其中取出m(m< =n)个数,列出所有可能的组合。一般来说,使用循环实现,但是逻辑复杂,不容易调试。而使用递归算法,可以大大简化程序。
使用递归实现一个算法时,首先要对问题进行降级处理,就是对于处理n的问题,要转化为n-1或者n-2,…..的问题。其次,就是要确定递归结束条件。如果没有递归结束条件,程序就无法结束,导致系统资源消耗殆尽。
首先我们分析一下:对1到n所有的整数求和的问题。传统的循环实现程序如下:
function sum(n:integer):integer;
var
I:integer;
Begin
Result:=0;
For I:=1 to n do
Result:=result+I;
End;
而用递归实现,我们可以得到sum(n)=n+sum(n-1),这就是降级后的结果;如果n=1,那么和肯定为1,不用再进行递归,这就是递归结束的条件。
所以这个问题可以用以下递归程序实现:
function sum(n:integer):integer;
Begin
If n=1 then
Result:=1
Else
Result:=result+sum(n-1);
End;
下面我们对组合问题进行分析。
要从n(假设这n个数为1到n)个数中取出m个数,我们可以先确定是否有第一个数,如果有1,那么从余下的n-1个数中取出m-1个就可以了;而要是没有1,则需要从余下的n-1个数中选出m个数。这样,我们就把问题进行了降级处理,那么什么时候递归结束呢?如果要从若干个数中取出0个,那么说明不需要再进行选取了,认为递归结束;另外一种情况是,要从p个数中选出p个数,这时确定的选法就是这p个数,所以也可以把这p个数作为结果,然后结束递归。这样,我们就确定了组合问题的降级处理和结束条件。
我们用过程select来实现组合选数。参数setvailable代表可供选择数的集合,m表示需要从集合setvailable中选取m个元素,setselected表示已经选出来的元素。
具体实现如下:
procedure select(setavailable:set of 1..n,m:integer;setselected:set of 1..n);
begin
if m=0 then exit; //不需要选择,结束递归
if CountOfElement(setavailable)=m then
//从m个数中选出m个,那么把setavailable和setselected的并集作为结果,结束递归
begin
puttoresult(setavailable+setselected);
exit
end;
//到此,如果没有结束,则需要对问题进行降级
select(setavailable-[FirstElement(setavailable)],m-1,setselected+[ FirstElement(setavailable)]);
//选中集合中的第一个元素,然后从余下的元素中选取m-1个元素
select(setavailable-[FirstElement(setavailable)],m,setselected);
//若不选择第一个元素,则从余下的元素中选取m个元素
end;
在上面的程序中,FirstElement从一个集合中取出最小的元素,CountOfElement计算一个集合中的元素个数,puttoresult把得到的组合记录下来,这些函数和过程的实现略去。
至此,组合选数的问题就解决了,从以上的程序中,我们可以看出,对于有些问题,用递归来实现非常简单,而且逻辑清晰。
========================结束=======================
下面是我写的代码。应该正确了
<?php /** * test */ function get_zhuhe($m, $n, $str=""){ if(is_array($m)==false){ echo "this is not a array!"; return; } if($n>$m){ echo "error n"; return; } $len = count($m); if($n==0){ echo $str . "<br>"; return; } if($len==$n){ echo $str . " "; foreach($m as $key){ echo $key . " "; } echo "<br>"; return; } $t = $m[$len-1]; unset($m[$len-1]); get_zhuhe($m, $n, $str); get_zhuhe($m, $n-1, $str . " " . $t); } get_zhuhe(array(1, 4, 5, 66, 88, 3, 10), 3); ?>
欢迎指正。