全排列算法(字典序,递归实现)
2014-09-14 22:18
381 查看
字典序算法如下:
设P是1~n的一个全排列:p=p1p2......pn=p1p2......pj-1pjpj+1......pk-1pkpk+1......pn
1)从排列的右端开始,找出第一个比右边数字小的数字的序号j(j从左端开始计算),即 j=max{i|pi<pi+1}<br/>
2)在pj的右边的数字中,找出所有比pj大的数中最小的数字pk,即k=max{i|pi>pj}(右边的数从右至左是递增的,
因此k是所有大于pj的数字中序号最大者)<br/>
3)对换pi,pk<br/>
4)再将pj+1......pk-1pkpk
+1pn倒转得到排列p''=p1p2.....pj-1pjpn.....pk+1pkpk-1.....pj+1,这就是排列p的下一个下一个排列。
例如839647521是数字1~9的一个排列。从它生成下一个排列的步骤如下: 自右至左找出排列中第一个比右边数字小的数字4 839647521
在该数字后的数字中找出比4大的数中最小的一个5 839647521 将5与4交换 839657421 将7421倒转 839651247
所以839647521的下一个排列是839651247。 839651247的下一个排列是839651274。
全排列递归算法实现
如果集合是{a,b,c},那么这个集合中元素的所有排列是{(a,b,c),(a,c,b),(b,a,c),(b,c,a),(c,a,b),(c,b,a)},显然,给定n个元素共有n!种不同的排列,如果给定集合是{a,b,c,d},可以用下面给出的简单算法产生其所有排列,即集合(a,b,c,d)的所有排列有下面的排列组成:
(1)以a开头后面跟着(b,c,d)的排列
(2)以b开头后面跟着(a,c,d)的排列
(3)以c开头后面跟着(a,b,d)的排列
(4)以d开头后面跟着(a,b,c)的排列,这显然是一种递归的思路,于是我们得到了以下的实现:
设P是1~n的一个全排列:p=p1p2......pn=p1p2......pj-1pjpj+1......pk-1pkpk+1......pn
1)从排列的右端开始,找出第一个比右边数字小的数字的序号j(j从左端开始计算),即 j=max{i|pi<pi+1}<br/>
2)在pj的右边的数字中,找出所有比pj大的数中最小的数字pk,即k=max{i|pi>pj}(右边的数从右至左是递增的,
因此k是所有大于pj的数字中序号最大者)<br/>
3)对换pi,pk<br/>
4)再将pj+1......pk-1pkpk
+1pn倒转得到排列p''=p1p2.....pj-1pjpn.....pk+1pkpk-1.....pj+1,这就是排列p的下一个下一个排列。
例如839647521是数字1~9的一个排列。从它生成下一个排列的步骤如下: 自右至左找出排列中第一个比右边数字小的数字4 839647521
在该数字后的数字中找出比4大的数中最小的一个5 839647521 将5与4交换 839657421 将7421倒转 839651247
所以839647521的下一个排列是839651247。 839651247的下一个排列是839651274。
public static void main(String[] args) { long l1 = System.currentTimeMillis(); System.out.println("请输入要对前n个数字进行排列:"); Scanner s = new Scanner(System.in); int n = s.nextInt(); int[] arry = new int ; for (int i = 0; i < arry.length; i++) { arry[i] = i + 1; } System.out.println(Arrays.toString(getInt(arry))); do { System.out.println(Arrays.toString(getInt(arry))); } while (next(arry)); long l2 = System.currentTimeMillis(); System.out.print("共耗时" + (l2 - l1) + "耗秒"); } private static int[] getInt(int[] arry) { int[] arry1 = new int[arry.length]; System.arraycopy(arry, 0, arry1, 0, arry.length); return arry1; } private static boolean next(int[] arry) { int pos1 = -1; int pos2 = -1; //从右到左,找到第一个比右边小的数,记录位置pos1 for (int i = arry.length - 1; i > 0; i--) { if (arry[i - 1] < arry[i]) { pos1 = i - 1; break; } } if (pos1 < 0) { return false; } //在pos1位置后的数字中找出比它大的数中最小的一个,然后交换位置,在逆转 for (int i = arry.length - 1; i > pos1; i--) { if (arry[i] > arry[pos1]) { pos2 = i; swap(arry, pos2, pos1); reserve(arry, pos1 + 1, arry.length - 1); break; } } if (pos2 < 0) { return false; } return true; } /** * * 逆转数组中第i个到第j个的数,比如数组为123,i=0,j=2,则逆转为321 * * @param arry * @param i * @param j */ private static void reserve(int[] arry, int i, int j) { for (; i <= j; i++, j--) { swap(arry, i, j); } } /** * 交换一个数组中第i个和第j个数的值 * * @param array * @param i * @param j */ private static void swap(int[] array, int i, int j) { int temp = array[j]; array[j] = array[i]; array[i] = temp; }
全排列递归算法实现
如果集合是{a,b,c},那么这个集合中元素的所有排列是{(a,b,c),(a,c,b),(b,a,c),(b,c,a),(c,a,b),(c,b,a)},显然,给定n个元素共有n!种不同的排列,如果给定集合是{a,b,c,d},可以用下面给出的简单算法产生其所有排列,即集合(a,b,c,d)的所有排列有下面的排列组成:
(1)以a开头后面跟着(b,c,d)的排列
(2)以b开头后面跟着(a,c,d)的排列
(3)以c开头后面跟着(a,b,d)的排列
(4)以d开头后面跟着(a,b,c)的排列,这显然是一种递归的思路,于是我们得到了以下的实现:
public static void main(String[] args) { char[] data={'a','b','c'}; permutation(data,0,data.length-1); } private static void permutation(char[] data, int start, int end) { int i,j; if(start==end){ for(i=0;i<=end;i++){ System.out.print(data[i]); } System.out.println(); }else{ for(j=start;j<=end;j++){ swap(data,j,start); permutation(data, start+1, end); swap(data,j,start); } } } private static void swap(char[] data,int j, int start) { char temp = data[j]; data[j] = data[start]; data[start] =temp; }
相关文章推荐
- 递归实现全排列算法
- 全排列算法非递归实现和递归实现
- 全排列算法的递归与非递归实现
- 递归实现全排列(按字典序)
- 全排列的实现字典序写法,递归也给附带写了
- 全排列算法的非递归实现与递归实现的方法(C++)
- 经典算法题2:递归和字典序的全排列算法
- 全排列算法的非递归实现
- 全排列算法的递归与非递归实现
- 全排列算法-递归与字典序的实现方法(Java)
- 全排列算法递归实现 C++
- 全排列算法非递归实现和递归实现
- 全排列算法的递归思想及实现
- 全排列算法【非递归活动数实现】
- 【转】全排列算法非递归实现和递归实现
- 全排列算法的递归实现
- 全排列算法的递归与非递归实现
- 递归实现的全排列算法
- 全排列算法(递归实现) 组合算法(递归,位运算实现)
- LeetCode:Permutations(全排列算法的递归与非递归实现)