《算法设计与分析之全排列.ppt》由会员分享,可在线阅读,更多相关《算法设计与分析之全排列.ppt(8页珍藏版)》请在金锄头文库上搜索。
1、全排列1、首先看最后两个数4, 5。 它们的全排列为4 5和5 4, 即以4开头的5的全排列和以5开头的4的全排列。由于一个数的全排列就是其本身,从而得到以上结果。2、再看后三个数3, 4, 5。它们的全排列为3 4 5、3 5 4、 4 3 5、 4 5 3、 5 3 4、 5 4 3 六组数。即以3开头的和4,5的全排列的组合、以4开头的和3,5的全排列的组合和以5开头的和3,4的全排列的组合.从而可以推断,设一组数p = r1, r2, r3, . ,rn, 全排列为perm(p),pn = p- rn。因此perm(p) = r1perm(p1), r2perm(p2), r3perm
2、(p3), . , rnperm(pn)。当n = 1时perm(p = r1。为了更容易理解,将整组数中的所有的数分别与第一个数交换,这样就总是在处理后n-1个数的全排列两个例子123的全排列-首先遍历元素,然后把遍历到的每一个元素都和第一个元素交换第一个和第一个交换 就是1和1交换 最后还是123那么就形成了 123 213 321 这样的3组(交换后 再换回来 还原成123 因为后面的交换都是在123的基础上交换的 所以swap要写2次)-检查每一组除了第一个之外的剩余元素, 如果这些元素个数是2,那么就对这剩下的2个元素全排列 就是123 132 , 213 231 , 321 312
3、 2个元素的全排列很简单 就是把这2个元素交换位置就OK)两个例子1234的全排列-首先遍历元素,然后把遍历到的每一个元素都和第一个元素交换那么就形成了 1234 2134 3214 4231 这样的4组-检查每一组除了第一个之外的剩余元素, 如1234剩余的是234,发现是3个元素那么问题就转换为求234的全排列了接下来也是一样 问题转换为求134, 214, 231的全排列像这样 总是对除了第一个之外的元素全排列, 每次元素的个数都在减少一个,求N个元素全排列最终就变成求2的元素的全排列了求求n n个元素的全排列。个元素的全排列。分析:分析:n=1 输出输出a1; n=2 输出输出a1 a
4、2; a2 a1; n=3 输出输出a1 a2 a3; a1 a3 a2; a2 a1 a3; a2 a3 a1; a3 a2 a1; a3 a1 a2;归纳:归纳:n=3时排列的分类时排列的分类(1)a1类:类:a1之后跟之后跟a2,a3的全排列;的全排列;(2)a2类:类:a2之后跟之后跟a1,a3的全排列;的全排列;(3)a3类:类:a3之后跟之后跟a2,a1的全排列。的全排列。将(1)中的a1,a2互换位置,得到(2);将(1)中的a1,a3互换位置,得到(3).可以用循环重复执行可以用循环重复执行“交换位置,后跟剩交换位置,后跟剩余序列的所有排列余序列的所有排列”;对剩余的序列再使;
5、对剩余的序列再使用该方法,直至没有用该方法,直至没有剩余序列剩余序列递归调递归调用用由排列组合的知识可知,n个元素的全排列共有n!种。n!可分解为n*(n-1)!种,而(n-1)!又分解为(n-1)(n-2)!种,依次类推。 若用一个数组an来保存1n之间的n个自然数,对于i =1n,每次使a1同ai交换后,对a2an中的n-1个元素进行全排列,然后再交换a1与ai的值,使它恢复为此次排列前的状态;同样,对于a3an区间内的n-2个元素进行全排列,然后再把交换的元素交换回来;依次类推,直到对an进行全排列时,输出整个数组的值,即得到一种排列结果。n=3 1 2 3 1 3 2 2 1 3 2
6、3 1 3 2 1 3 1 2n=4 1 2 3 4 1 2 4 3 1 3 2 4 1 3 4 2 1 4 3 2 1 4 2 3 2 1 3 4 2 1 4 3 2 3 1 4 2 3 4 1 2 4 3 1 2 4 1 3 3 2 1 4 3 2 4 1 3 1 2 4 3 1 4 2 3 4 1 2 3 4 2 1 4 2 3 1 4 2 1 3 4 3 2 1 4 3 1 2 4 1 3 2 4 1 2 3procedure range(a,k,n)if k=n then print(a)else for i k to n do ak ai; call range(a,k+1,n);
7、 ak ai; endifendrange;对于对于n个元素个元素a=(a1a2akan),设过程设过程range(a, k, n)是求是求a的第的第k到第到第n个元素的全排列。个元素的全排列。算法如下:算法如下:procedure range(a,k,n); 当当k指向最后元素时,指向最后元素时, 递归终止,输出相应的字符串递归终止,输出相应的字符串a 否则否则 i从从k到到n重复执行:重复执行: 交换交换ak与与ai ; range(a, k+1, n); 交换交换ak与与ai ;endrange; 1.Void Perm(Type list,int k, int m)2./递归的产生前缀
8、是list0:k-1后缀是listk:m的全排列的所有排列3.if(k=m)/只剩下一个元素4.for(int i=0;i=m;i+) 5. coutlisti;6.coutendl;7.8.else/还有多个元素待排列,递归产生排列9.for(int i=k;i=m;i+)10.Swap(listk,listi);11.Perm(list,k+1,m);12.Swap(listk,listi;13.14.为什么需要交换两次举个例子 比如现在数组的数据是 123 算法是这样的 1和3先交换 变成了321 然后递归 2和1交换 变成了312 然后递归 满足if语句条件输出 然后在逐层反回 还是 123 只不过这次应该是23交换了 这样在递归 才有能把所有的组合找出来 如果你第二次不交换i j 那就是321进入下个循环了 所以会漏掉很多组合