在前一篇文章n个球中取出m个球中介绍过组合与排列,如果是需要计算n个元素的全排列个数,那么我们只需要通过A(n,n)就能得到结果,但是我们需要将其打印出来,那应该要怎么做呢?
【ABC】【ACB】【BAC】【BCA】【CAB】【CBA】
public static void printfArranager(char[] data,int k){
if(k==data.length){
for(int i=0;i<data.length;i++)
System.out.print(data[i]+" ");
System.out.println();
}
//从第一个元素开始,不断与后面的元素进行交换
for(int i=k;i<data.length;i++){
{char t=data[k]; data[k] = data[i]; data[i] = t;}
//交换之后,将得到的新arr递归到【第二层】的函数,并让k+1,从第二个元素开始交换
printfArranager(data,k+1);
//交换之后需要进行回溯,如果不进行回溯,那么上面改变的arr会对本次循环之后的其他循环的交换造成影响
{char t=data[k]; data[k] = data[i]; data[i] = t;}
}
}
测试代码:
public static void main(String[] args) {
char data[] = "ABC".toCharArray();
printfArrange1(data,0);
}
为了能更好的帮助理解代码,下面我们来画一下的递归的内存分布图(为了便于观察递归,主要就画一下栈区的结构了):
结合上面的图,我们再分析一下printfArranager的栈区数据的变化:
//程序执行,main函数入栈,传入参数,第一次执行printfArrangel,printf函数入栈
按顺序,整个执行流程如下:
第一层: arr :ABC k = 0 ; i=k,
第一层第一次循环: arr[0]与arr[0]进行交换,结果不变。arr:ABC,递归下一层
第二层: arr:ABC k = 1;i=k
第二层第一次循环:arr[1]与arr[1]进行交换,结果不变,arr:ABC,递归下一层
第三层: arr:ABC k = 2,i=k
第三层:循环条件i<arr.length不成立,不执行后面的程序,故递归到此结束,根据
判断打印当前所有元素ABC之后开始回调,回到第二层的第一次循环调用printf函数
的后面,进行回溯操作,将当前循环的元素还原,以便第二次循环使用,到此,第二
层第一次循环结束,开始第二次循环
第二层第二次循环 arr:ABC k=1,i=k+1(原有的条件保持不变,之所以要回溯就是因
为要保证不同层之间的数据相互不影响),arr[k]与arr[i+1]进行交换,交换之后
arr:ACB,递归到下一层
第三层:循环条件i<arr.length不成立,不执行后面的程序,故递归到
此结束,根据判断打印当前所有元素ACB之后开始回调,回到第二层的第二次循环调
用printf函数的后面,进行回溯操作,到此,第二层第二次循环结束,开始第三次循
环
第二层第三次循环:arr:ABC k = 1,i=k+2,因为i超过了arr的界限,所以第二层的
递归也到此结束,继续回到第一层的第一次循环的printf函数后面,进行回溯,进入
第一层第二次循环
第一层第二次循环:arr:ABC k = 0;i=k+1,arr[0]与arr[1]交换位置,交换之后
arr:BAC,递归到下一层的新的循环
第二层第一次循环:arr:BAC,k=1,i=k,arr[1]与arr[1]交换位置,交换之后,arr:
BAC,递归到下一层的新的循环
第三层:arr:BAC k=i=2,循环条件i<arr.length不成立,不执行后面的
程序,故递归到此结束,根据判断打印当前所有元素BAC之后开始回调,回到第二层
的第二次循环调用
第二层第二次循环:arr:BAC,k=1,i=2,arr[1]与arr[2]交换位置,arr:BCA,递归到下一层。
第三层:arr:BCA,i<arr.length循环条件不成立,结束递归,打印BCA之后回到第二层第二次循环执行回溯,因为i=2,所以第二层的循环也结束,回第一层
第一层第三次循环:arr:ABC k=0,i=2,arr[0]与arr[2]进行交换,arr:CBA,交换之后,又开始递归
......就是一个循环的过程,写了两个过程了,第三也是一模一样的,就不写了,实
在是写不动了emmm
以上就是递归的思路分析及内存的执行机制,如果还有其他思路的大佬请务必分享给我,非常感谢!!!