[续]全排列的非递归实现
2012-08-10 09:04 coodoing 阅读(890) 评论(0) 编辑 收藏 举报前文提到过全排列的递归实现,这里在简单的介绍下全排列的非递归实现。
以6个数字的全排列为例说明,相当于用1,2,3,4,5,6 构造一个六位数,每一位上取一个数,这样一共有6!中方法。
很显然,这6!个数是有大小的,如果按从小到大排列,示意如下:
1 2 3 4 5 6
1 2 3 4 6 5
1 2 3 5 4 6
…………
6 5 4 3 2 1
显然 , 每个数有唯一后继 ! 如果找到一个数没有后继(6 5 4 3 2 1),则停止。
那么问题的重点在于如何判断是否有后继,以及怎样找到后继 ! 是否有后继很好判断,唯一没有后继的只有654321,它的特点是每位的数字比后面的大!如何找到后继,思路很清楚,即对于一个数,找到一个比它大的、最小的数!
来考虑"926510"这个字符串,我们从后向前找第一双相邻的递增数字,"10"、"52"都是非递增的,"26 "即满足要求,称前一个数字2为替换数,替换数的下标称为替换点,再从后往前找一个比替换数大的最小数(这个数必然存在),0、1都不行,5可以,将5和2交换得到"956210",然后再将替换点后的字符串"6220"颠倒即得到"950226"。同理:比如926540的后继应该是946520,而不是956240。
1: public class NonRecursivePermutation {
2:
3: static int[] arr = new int[] { 1, 2, 3, 4, 5, 6 };
4: static int count = 1;
5:
6: // 反转区间
7: private static void reverse(int[] arr, int pBegin, int pEnd) {
8: while (pBegin < pEnd)
9: swap(arr, pBegin++, pEnd--);
10: }
11:
12: private static void swap(int[] arr, int i, int j) {
13: int temp;
14: temp = arr[i];
15: arr[i] = arr[j];
16: arr[j] = temp;
17: }
18:
19: private static boolean hasNext() {
20: for (int i = arr.length - 1; i > 0; i--) {
21: if (arr[i] > arr[i - 1])
22: return true;
23: }
24: return false;
25: }
26:
27: private static void next() {
28: int len = arr.length;
29: int replace = 0; // 需替换数
30: int firstR = 0; // 从后向前找比替换数大的第一个数
31: // 找降序的相邻2数,前一个数即需替换数
32: for (int i = len - 1; i > 0; i--) {
33: if (arr[i] > arr[i - 1]) {
34: replace = i - 1;
35: break;
36: }
37: }
38:
39: //System.out.println("需替换数位置:" + replace);
40:
41: // 从后向前找比替换数大的第一个数
42: // 比如926540的后继应该是946520,而不是956240
43: for (int i = len - 1; i > replace; i--) {
44: if (arr[i] > arr[replace]) {
45: firstR = i;
46: break; //找到之后直接退出
47: }
48: }
49:
50: //System.out.println("替换数位置:" + firstR);
51:
52: // replace与firstR交换
53: swap(arr, replace, firstR);
54: // 替换数后的数全部反转
55: reverse(arr, replace + 1, len - 1);
56:
57: count++;
58: print();
59: }
60:
61: private static void print() {
62: for (int i = 0; i < arr.length; i++)
63: System.out.print(arr[i] + " ");
64: System.out.println();
65: }
66:
67: /**
68: * @param args
69: */
70: public static void main(String[] args) {
71:
72: while (hasNext() == true) {
73: next();
74: }
75: System.out.println("数组完全反转后的结果:");
76: reverse(arr, 0, arr.length - 1);
77: print();
78: System.out.println("全排列的数目为:" + count);
79:
80: /*********************/
81: System.out.println("数组是否存在后继:" + hasNext());
82: System.out.println("数组一次替换后的结果:");
83: next();
84: }
85:
86: }
除了上述的找后继实现外,还有一种基于变进制数的实现。这里可以用来作为一个参考。
最后附加利用python中itertool模块求全排列的简短代码。
import itertools
list(itertools.permutations([1,2,3]))
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现