欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

关于递归(全排序perm问题等,待补充)

程序员文章站 2022-03-03 08:23:35
...

将集合X的全排序记为perm(X)

所以,对于一组数 r={r1,r2,…rn},记 Ri=r-{ri}。(1<=i<=n)

当 n=1 , perm(r)=(r)

当 n>1,perm(r)= r1perm(R1)+ r2perm(R2)+…+ rnperm(Rn)

R1,R2…再进行分解,不断地将排序的数,即perm(list,k,m)减少,直到剩下一个数,即 k = =m,可从一个递归出来,回到原来的 for循环,再把下一个数与此时的 list(k)交换,再次执行,到 k==m 再回到上一层 for 循环…直到第一层的 for 循环执行完。由此构成一个递归。

代码:

public static void perm(Object []list, int k, int m){
	if(k==m){
			for(i=0;i<=m;i++)     //输出每一趟排序,前面加上数组中不参与排序的其它数
					System.out.print(list[i]);  
			System.out.println();
	}
	else
		for(int i=k; i<=m; i++){    //★★每个子递归都要进行自己的这个for循环
				MyMath.swap(list, k, i);   // k后面每个数(**包括自己**)都要与它交换位置
				perm(list, k+1 ,m);
				MyMath.swap(list, k, i);
		}
}

整个递归的规模:变小→变大→变小→变大…(不断循环)…

举个栗子:

现在有一组数,list= {5,6,7,8},要求perm(list,0,3)

(★为了更加清晰展现排序过程,下列数字均为实际数字,而非数组下标!★)

第一趟最外层 for 循环:

                        7,8        //最里层for循环第一次输出
               	      ↗
5,6,perm(list,7,8)
             	      ↘
                        8,7	     //位置交换,第二次输出
                   
       然后 7 和 6 交换 
                  
                        6,8
          	          ↗
5,7,perm(list,6,8)
               		  ↘
                 	    8,6
                   
       然后  8 和 6 交换    
          
             	        7,6
            		  ↗
5,8,perm(list,7,6)
               		  ↘
           		         6,7

以上共产生六组数
结束后进入第二趟最外层 for 循环,因为 总共有四个数要排序,故总共4层
以此类推
可得到perm(list,0,3)

总结,其实这个算法很简单,因为它的每一个子递归都具有完全相同的特质。

从代码段第二个 for 循环段中就可以看的很明显:
每一次 第一个要排序的数到最后一个,依次跟第一个换位置,然后再分解或者输出。

直到剩下一个数,此时就能从这一底层递归跑出来了。

(然后再回去for循环 i++,让下一个数与第一个数交换位置。这层for循环执行完了,再回上层for执行…)